From 4e32148ac59ba6b4f3acc79a3b782cd3556f941a Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Sat, 1 Sep 2007 01:13:44 +0000 Subject: [PATCH] Sync with HEAD for OL 2.4.5 --- COPYRIGHT | 6 +- README | 4 - build/config.guess | 2 +- build/config.sub | 2 +- build/ltmain.sh | 4 +- build/openldap.m4 | 151 +- build/top.mk | 5 +- clients/tools/common.c | 335 ++- clients/tools/ldapcompare.c | 16 +- clients/tools/ldapdelete.c | 8 +- clients/tools/ldapexop.c | 21 +- clients/tools/ldapmodify.c | 7 +- clients/tools/ldapmodrdn.c | 8 +- clients/tools/ldappasswd.c | 20 +- clients/tools/ldapwhoami.c | 25 +- configure | 1111 ++++++++-- configure.in | 152 +- contrib/ldapc++/src/ac/time.h | 4 +- contrib/ldaptcl/configure | 3 +- contrib/ldaptcl/configure.in | 3 +- contrib/ldaptcl/neoXldap.c | 4 +- contrib/slapd-modules/addpartial/COPYRIGHT | 10 + contrib/slapd-modules/addpartial/LICENSE | 47 + contrib/slapd-modules/addpartial/Makefile | 12 + contrib/slapd-modules/addpartial/README | 61 + .../addpartial/addpartial-overlay.c | 434 ++++ contrib/slapd-modules/allop/allop.c | 3 +- contrib/slapd-modules/passwd/radius.c | 32 +- contrib/slapd-modules/smbk5pwd/smbk5pwd.c | 6 +- doc/devel/toolargs | 2 +- .../draft-haripriya-dynamicgroup-xx.txt | 1400 ++++++++++++ doc/drafts/draft-wahl-ldap-session-xx.txt | 1120 ++++++++++ .../draft-zeilenga-ldap-dontusecopy-xx.txt | 150 +- doc/drafts/draft-zeilenga-ldap-noop-xx.txt | 88 +- ...t-xx.txt => draft-zeilenga-ldap-relax.txt} | 302 +-- doc/man/man1/ldapcompare.1 | 12 + doc/man/man1/ldapmodrdn.1 | 6 + doc/man/man1/ldapsearch.1 | 13 +- doc/man/man3/Deprecated | 2 +- doc/man/man3/lber-decode.3 | 6 +- doc/man/man3/lber-encode.3 | 2 +- doc/man/man3/lber-memory.3 | 2 +- doc/man/man3/lber-sockbuf.3 | 3 +- doc/man/man3/lber-types.3 | 9 +- doc/man/man3/ldap.3 | 14 +- doc/man/man3/ldap_bind.3 | 2 +- doc/man/man3/ldap_controls.3 | 61 +- doc/man/man3/ldap_controls.3.links | 6 +- doc/man/man3/ldap_first_message.3 | 3 +- doc/man/man3/ldap_first_reference.3 | 3 +- doc/man/man3/ldap_get_option.3 | 4 +- doc/man/man3/ldap_parse_sort_control.3 | 3 +- doc/man/man3/ldap_parse_vlv_control.3 | 5 +- doc/man/man3/ldap_rename.3 | 2 +- doc/man/man3/ldap_result.3 | 9 +- doc/man/man3/ldap_schema.3 | 9 +- doc/man/man3/ldap_search.3 | 2 +- doc/man/man3/ldap_sort.3 | 2 +- doc/man/man3/ldap_sync.3 | 11 +- doc/man/man3/ldap_url.3 | 4 +- doc/man/man5/ldap.conf.5 | 9 +- doc/man/man5/ldif.5 | 2 + doc/man/man5/slapd-bdb.5 | 12 +- doc/man/man5/slapd-config.5 | 174 +- doc/man/man5/slapd-ldap.5 | 7 + doc/man/man5/slapd-ldbm.5 | 137 +- doc/man/man5/slapd-meta.5 | 13 +- doc/man/man5/slapd-monitor.5 | 3 +- doc/man/man5/slapd-null.5 | 2 +- doc/man/man5/slapd-relay.5 | 102 +- doc/man/man5/slapd-sql.5 | 4 +- doc/man/man5/slapd.access.5 | 4 +- doc/man/man5/slapd.backends.5 | 2 +- doc/man/man5/slapd.conf.5 | 145 +- doc/man/man5/slapd.overlays.5 | 20 + doc/man/man5/slapd.plugin.5 | 4 +- doc/man/man5/slapd.replog.5 | 167 -- doc/man/man5/slapo-accesslog.5 | 2 +- doc/man/man5/slapo-auditlog.5 | 2 +- doc/man/man5/slapo-chain.5 | 2 +- doc/man/man5/slapo-constraint.5 | 57 + doc/man/man5/slapo-dds.5 | 74 +- doc/man/man5/slapo-dyngroup.5 | 48 + doc/man/man5/slapo-dynlist.5 | 30 +- doc/man/man5/slapo-memberof.5 | 114 + doc/man/man5/slapo-pcache.5 | 26 +- doc/man/man5/slapo-ppolicy.5 | 4 +- doc/man/man5/slapo-refint.5 | 2 +- doc/man/man5/slapo-retcode.5 | 2 +- doc/man/man5/slapo-rwm.5 | 34 +- doc/man/man5/slapo-syncprov.5 | 5 +- doc/man/man5/slapo-translucent.5 | 2 +- doc/man/man5/slapo-unique.5 | 140 +- doc/man/man5/slapo-valsort.5 | 2 +- doc/man/man8/slapadd.8 | 8 +- doc/man/man8/slapauth.8 | 2 +- doc/man/man8/slapcat.8 | 12 +- doc/man/man8/slapd.8 | 14 +- doc/man/man8/slapdn.8 | 2 +- doc/man/man8/slaptest.8 | 11 +- doc/man/man8/slurpd.8 | 160 -- doc/rfc/INDEX | 1 + doc/rfc/rfc5020.txt | 283 +++ include/Makefile.in | 4 + include/ac/alloca.h | 2 +- include/ac/crypt.h | 2 +- include/ac/dirent.h | 8 +- include/ac/errno.h | 2 +- include/ac/socket.h | 22 +- include/ac/termios.h | 2 +- include/ac/time.h | 4 +- include/ac/unistd.h | 8 +- include/ac/wait.h | 2 +- include/lber.h | 26 +- include/ldap.h | 76 +- include/ldap_config.hin | 3 + include/ldap_pvt.h | 32 +- include/ldap_pvt_thread.h | 5 - include/lutil.h | 7 + include/portable.hin | 41 +- include/slapi-plugin.h | 6 +- libraries/liblber/bprint.c | 14 +- libraries/liblber/decode.c | 78 +- libraries/liblber/encode.c | 58 + libraries/liblber/io.c | 24 +- libraries/liblber/lber-int.h | 19 +- libraries/liblber/memory.c | 21 +- libraries/liblber/sockbuf.c | 40 +- libraries/libldap/Makefile.in | 4 +- libraries/libldap/abandon.c | 5 +- libraries/libldap/addentry.c | 5 +- libraries/libldap/controls.c | 170 +- libraries/libldap/dds.c | 5 +- libraries/libldap/extended.c | 1 + libraries/libldap/getdn.c | 263 +-- libraries/libldap/init.c | 4 + libraries/libldap/ldap-int.h | 10 +- libraries/libldap/ldap.conf | 2 +- libraries/libldap/ldap_sync.c | 33 +- libraries/libldap/os-ip.c | 10 +- libraries/libldap/os-local.c | 25 +- libraries/libldap/pagectrl.c | 17 +- libraries/libldap/ppolicy.c | 19 +- libraries/libldap/request.c | 36 +- libraries/libldap/result.c | 61 +- libraries/libldap/search.c | 5 +- libraries/libldap/sortctrl.c | 20 +- libraries/libldap/stctrl.c | 301 +++ libraries/libldap/test.c | 3 +- libraries/libldap/tls.c | 1585 ++++++++++++-- libraries/libldap/url.c | 175 +- libraries/libldap/urltest.c | 2 + libraries/libldap/vlvctrl.c | 14 +- libraries/libldap_r/Makefile.in | 4 +- libraries/libldap_r/thr_debug.c | 77 +- libraries/libldap_r/thr_posix.c | 159 +- libraries/libldap_r/tpool.c | 586 +++-- libraries/liblutil/detach.c | 4 +- libraries/liblutil/getpass.c | 2 +- libraries/liblutil/getpeereid.c | 95 +- libraries/liblutil/ldif.c | 3 + libraries/liblutil/lockf.c | 8 +- libraries/liblutil/passfile.c | 5 +- libraries/liblutil/sasl.c | 2 + libraries/liblutil/sockpair.c | 3 +- libraries/liblutil/uuid.c | 54 +- servers/Makefile.in | 2 +- servers/slapd/Makefile.in | 4 +- servers/slapd/abandon.c | 23 +- servers/slapd/aci.c | 1 + servers/slapd/acl.c | 6 +- servers/slapd/ad.c | 44 +- servers/slapd/add.c | 68 +- servers/slapd/alock.c | 2 +- servers/slapd/at.c | 16 +- servers/slapd/attr.c | 7 +- servers/slapd/back-bdb/add.c | 2 +- servers/slapd/back-bdb/back-bdb.h | 44 +- servers/slapd/back-bdb/bind.c | 28 +- servers/slapd/back-bdb/cache.c | 57 +- servers/slapd/back-bdb/compare.c | 2 +- servers/slapd/back-bdb/config.c | 19 +- servers/slapd/back-bdb/dbcache.c | 2 +- servers/slapd/back-bdb/delete.c | 4 +- servers/slapd/back-bdb/dn2entry.c | 2 +- servers/slapd/back-bdb/dn2id.c | 10 +- servers/slapd/back-bdb/filterindex.c | 117 +- servers/slapd/back-bdb/id2entry.c | 17 +- servers/slapd/back-bdb/idl.c | 4 +- servers/slapd/back-bdb/index.c | 40 +- servers/slapd/back-bdb/init.c | 148 +- servers/slapd/back-bdb/key.c | 2 +- servers/slapd/back-bdb/modify.c | 6 +- servers/slapd/back-bdb/modrdn.c | 4 +- servers/slapd/back-bdb/monitor.c | 277 ++- servers/slapd/back-bdb/proto-bdb.h | 41 +- servers/slapd/back-bdb/referral.c | 10 +- servers/slapd/back-bdb/search.c | 19 +- servers/slapd/back-bdb/tools.c | 144 +- servers/slapd/back-dnssrv/bind.c | 40 +- servers/slapd/back-dnssrv/init.c | 9 +- servers/slapd/back-ldap/add.c | 7 +- servers/slapd/back-ldap/back-ldap.h | 10 + servers/slapd/back-ldap/bind.c | 333 ++- servers/slapd/back-ldap/chain.c | 97 +- servers/slapd/back-ldap/compare.c | 7 +- servers/slapd/back-ldap/config.c | 176 +- servers/slapd/back-ldap/delete.c | 7 +- servers/slapd/back-ldap/distproc.c | 30 +- servers/slapd/back-ldap/extended.c | 144 +- servers/slapd/back-ldap/init.c | 9 +- servers/slapd/back-ldap/modify.c | 11 +- servers/slapd/back-ldap/modrdn.c | 7 +- servers/slapd/back-ldap/proto-ldap.h | 21 + servers/slapd/back-ldap/search.c | 81 +- servers/slapd/back-ldif/ldif.c | 378 ++-- servers/slapd/back-meta/add.c | 7 +- servers/slapd/back-meta/back-meta.h | 11 +- servers/slapd/back-meta/bind.c | 230 +- servers/slapd/back-meta/compare.c | 7 +- servers/slapd/back-meta/config.c | 94 +- servers/slapd/back-meta/delete.c | 7 +- servers/slapd/back-meta/init.c | 10 +- servers/slapd/back-meta/map.c | 18 +- servers/slapd/back-meta/modify.c | 7 +- servers/slapd/back-meta/modrdn.c | 7 +- servers/slapd/back-meta/search.c | 215 +- servers/slapd/back-monitor/back-monitor.h | 8 +- servers/slapd/back-monitor/bind.c | 7 +- servers/slapd/back-monitor/compare.c | 2 +- servers/slapd/back-monitor/database.c | 106 + servers/slapd/back-monitor/init.c | 283 ++- servers/slapd/back-monitor/log.c | 2 +- servers/slapd/back-monitor/modify.c | 2 +- servers/slapd/back-monitor/operation.c | 8 +- .../slapd/back-monitor/proto-back-monitor.h | 27 + servers/slapd/back-monitor/time.c | 81 +- servers/slapd/back-null/null.c | 21 +- servers/slapd/back-perl/SampleLDAP.pm | 198 +- servers/slapd/back-perl/bind.c | 10 + servers/slapd/back-perl/close.c | 5 +- servers/slapd/back-perl/init.c | 7 +- servers/slapd/back-relay/Makefile.in | 4 +- servers/slapd/back-relay/config.c | 181 -- servers/slapd/back-relay/init.c | 128 +- servers/slapd/back-relay/op.c | 182 +- servers/slapd/back-relay/proto-back-relay.h | 1 - servers/slapd/back-shell/bind.c | 10 + servers/slapd/back-shell/init.c | 8 +- servers/slapd/back-shell/modify.c | 2 +- servers/slapd/back-shell/shell.h | 10 +- servers/slapd/back-sql/add.c | 2 +- servers/slapd/back-sql/back-sql.h | 80 +- servers/slapd/back-sql/bind.c | 29 +- servers/slapd/back-sql/compare.c | 4 +- servers/slapd/back-sql/config.c | 15 +- servers/slapd/back-sql/delete.c | 529 +++-- servers/slapd/back-sql/entry-id.c | 117 +- servers/slapd/back-sql/init.c | 169 +- servers/slapd/back-sql/modify.c | 12 +- servers/slapd/back-sql/modrdn.c | 16 +- servers/slapd/back-sql/operational.c | 2 +- servers/slapd/back-sql/proto-sql.h | 28 +- .../rdbms_depend/mysql/testdb_create.sql | 13 +- .../rdbms_depend/mysql/testdb_data.sql | 3 + .../rdbms_depend/mysql/testdb_metadata.sql | 7 + .../rdbms_depend/pgsql/testdb_create.sql | 8 + .../rdbms_depend/pgsql/testdb_data.sql | 3 + .../rdbms_depend/pgsql/testdb_metadata.sql | 4 + servers/slapd/back-sql/schema-map.c | 47 +- servers/slapd/back-sql/search.c | 282 ++- servers/slapd/back-sql/sql-wrap.c | 331 +-- servers/slapd/backend.c | 354 +-- servers/slapd/backglue.c | 13 +- servers/slapd/backover.c | 22 +- servers/slapd/bconfig.c | 1069 +++++---- servers/slapd/bind.c | 49 +- servers/slapd/cancel.c | 8 +- servers/slapd/compare.c | 89 +- servers/slapd/config.c | 97 +- servers/slapd/config.h | 11 +- servers/slapd/connection.c | 86 +- servers/slapd/controls.c | 413 +++- servers/slapd/cr.c | 2 +- servers/slapd/daemon.c | 80 +- servers/slapd/delete.c | 40 +- servers/slapd/dn.c | 92 +- servers/slapd/entry.c | 31 +- servers/slapd/extended.c | 28 +- servers/slapd/filter.c | 18 +- servers/slapd/filterentry.c | 4 +- servers/slapd/init.c | 9 +- servers/slapd/ldapsync.c | 41 +- servers/slapd/limits.c | 2 - servers/slapd/main.c | 24 +- servers/slapd/modify.c | 170 +- servers/slapd/modrdn.c | 98 +- servers/slapd/module.c | 3 +- servers/slapd/mr.c | 83 +- servers/slapd/oc.c | 22 +- servers/slapd/oidm.c | 14 +- servers/slapd/operation.c | 18 +- servers/slapd/overlays/Makefile.in | 10 +- servers/slapd/overlays/accesslog.c | 419 +++- servers/slapd/overlays/auditlog.c | 9 +- servers/slapd/overlays/collect.c | 199 +- servers/slapd/overlays/constraint.c | 26 +- servers/slapd/overlays/dds.c | 81 +- servers/slapd/overlays/dyngroup.c | 153 +- servers/slapd/overlays/dynlist.c | 320 ++- servers/slapd/overlays/memberof.c | 1947 +++++++++++++++++ servers/slapd/overlays/pcache.c | 1879 ++++++++++++++-- servers/slapd/overlays/ppolicy.c | 41 +- servers/slapd/overlays/refint.c | 266 ++- servers/slapd/overlays/retcode.c | 18 +- servers/slapd/overlays/rwm.c | 702 ++++-- servers/slapd/overlays/rwm.h | 48 +- servers/slapd/overlays/rwmconf.c | 9 - servers/slapd/overlays/rwmdn.c | 108 - servers/slapd/overlays/rwmmap.c | 36 +- servers/slapd/overlays/seqmod.c | 7 +- servers/slapd/overlays/syncprov.c | 108 +- servers/slapd/overlays/translucent.c | 20 +- servers/slapd/overlays/unique.c | 1307 ++++++++--- servers/slapd/overlays/valsort.c | 42 +- servers/slapd/passwd.c | 13 +- servers/slapd/proto-slap.h | 95 +- servers/slapd/repl.c | 555 ----- servers/slapd/result.c | 12 +- servers/slapd/sasl.c | 40 +- servers/slapd/saslauthz.c | 4 +- servers/slapd/schema/core.schema | 13 +- servers/slapd/schema/dyngroup.schema | 23 +- servers/slapd/schema_check.c | 38 +- servers/slapd/schema_init.c | 874 ++++++-- servers/slapd/schema_prep.c | 14 +- servers/slapd/schemaparse.c | 41 +- servers/slapd/search.c | 20 +- servers/slapd/sets.h | 2 +- servers/slapd/sl_malloc.c | 2 +- servers/slapd/slap.h | 725 +++--- servers/slapd/slapacl.c | 11 +- servers/slapd/slapadd.c | 157 +- servers/slapd/slapauth.c | 4 +- servers/slapd/slapcommon.c | 39 +- servers/slapd/slapcommon.h | 4 + servers/slapd/slapi/slapi.h | 6 +- servers/slapd/slapi/slapi_ops.c | 8 +- servers/slapd/slapi/slapi_overlay.c | 15 +- servers/slapd/slapi/slapi_pblock.c | 4 +- servers/slapd/slapi/slapi_utils.c | 10 +- servers/slapd/slaptest.c | 4 +- servers/slapd/syncrepl.c | 528 +++-- servers/slapd/syntax.c | 92 +- servers/slapd/unbind.c | 3 +- servers/slapd/value.c | 145 +- servers/slurpd/DESIGN | 51 - servers/slurpd/Makefile.in | 67 - servers/slurpd/NOTES | 67 - servers/slurpd/admin.c | 61 - servers/slurpd/args.c | 181 -- servers/slurpd/ch_malloc.c | 158 -- servers/slurpd/config.c | 675 ------ servers/slurpd/fm.c | 274 --- servers/slurpd/globals.c | 100 - servers/slurpd/globals.h | 89 - servers/slurpd/ldap_op.c | 918 -------- servers/slurpd/lock.c | 144 -- servers/slurpd/main.c | 355 --- servers/slurpd/nt_svc.c | 110 - servers/slurpd/proto-slurp.h | 113 - servers/slurpd/re.c | 793 ------- servers/slurpd/reject.c | 155 -- servers/slurpd/replica.c | 83 - servers/slurpd/replog.c | 169 -- servers/slurpd/ri.c | 285 --- servers/slurpd/rq.c | 444 ---- servers/slurpd/sanity.c | 225 -- servers/slurpd/slurp.h | 415 ---- servers/slurpd/st.c | 331 --- tests/Makefile.in | 2 +- tests/README | 2 +- tests/data/dynlist.out | 29 + tests/data/slapd-aci.conf | 5 +- tests/data/slapd-acl.conf | 4 +- tests/data/slapd-cache-master.conf | 2 - tests/data/slapd-chain1.conf | 4 +- tests/data/slapd-chain2.conf | 4 +- tests/data/slapd-component.conf | 1 - tests/data/slapd-config-undo.conf | 4 +- tests/data/slapd-dds.conf | 3 - tests/data/slapd-deltasync-master.conf | 6 +- tests/data/slapd-deltasync-slave.conf | 2 - tests/data/slapd-dn.conf | 2 - tests/data/slapd-dynamic.ldif | 2 +- tests/data/slapd-dynlist.conf | 8 +- tests/data/slapd-emptydn.conf | 4 - tests/data/slapd-glue-syncrepl1.conf | 18 +- tests/data/slapd-glue-syncrepl2.conf | 21 +- tests/data/slapd-glue.conf | 15 - tests/data/slapd-idassert.conf | 8 +- tests/data/slapd-ldapglue.conf | 2 - tests/data/slapd-ldapgluegroups.conf | 2 - tests/data/slapd-ldapgluepeople.conf | 2 - tests/data/slapd-limits.conf | 2 - tests/data/slapd-master.conf | 1 - tests/data/slapd-meta2.conf | 1 - tests/data/slapd-ppolicy.conf | 2 +- tests/data/slapd-proxycache.conf | 4 +- tests/data/slapd-pw.conf | 4 +- tests/data/slapd-ref-slave.conf | 4 +- tests/data/slapd-referrals.conf | 1 - tests/data/slapd-refint.conf | 2 - tests/data/slapd-relay.conf | 9 +- tests/data/slapd-repl-master.conf | 58 - tests/data/slapd-repl-slave-remote.conf | 2 +- tests/data/slapd-repl-slave.conf | 59 - tests/data/slapd-retcode.conf | 2 - tests/data/slapd-schema.conf | 1 - tests/data/slapd-syncrepl-master.conf | 2 - tests/data/slapd-syncrepl-multiproxy.conf | 2 - tests/data/slapd-syncrepl-slave-persist1.conf | 2 - tests/data/slapd-syncrepl-slave-persist2.conf | 2 - tests/data/slapd-syncrepl-slave-persist3.conf | 2 - tests/data/slapd-syncrepl-slave-refresh1.conf | 3 - tests/data/slapd-syncrepl-slave-refresh2.conf | 3 - tests/data/slapd-translucent-local.conf | 4 +- tests/data/slapd-translucent-remote.conf | 3 - tests/data/slapd-unique.conf | 11 +- tests/data/slapd-valsort.conf | 4 +- tests/data/slapd-whoami.conf | 4 +- tests/data/slapd.conf | 2 - tests/data/sql-read.out | 239 +- tests/data/sql-write.out | 102 + tests/data/test.schema | 2 +- tests/progs/slapd-addel.c | 18 +- tests/progs/slapd-bind.c | 30 +- tests/progs/slapd-common.c | 10 +- tests/progs/slapd-modify.c | 18 +- tests/progs/slapd-modrdn.c | 18 +- tests/progs/slapd-read.c | 62 +- tests/progs/slapd-search.c | 110 +- tests/progs/slapd-tester.c | 224 +- tests/run.in | 9 +- tests/scripts/all | 15 +- tests/scripts/defines.sh | 24 +- tests/scripts/its-all | 9 +- tests/scripts/sql-all | 9 +- tests/scripts/sql-test000-read | 77 +- tests/scripts/test007-replication | 348 --- tests/scripts/test017-syncreplication-refresh | 2 +- tests/scripts/test018-syncreplication-persist | 23 + tests/scripts/test021-certificate | 12 +- tests/scripts/test023-refint | 75 + tests/scripts/test024-unique | 461 +++- tests/scripts/test034-translucent | 13 +- tests/scripts/test042-valsort | 3 + tests/scripts/test043-delta-syncrepl | 4 +- tests/scripts/test044-dynlist | 108 +- tests/scripts/test045-syncreplication-proxied | 2 +- tests/scripts/test049-sync-config | 19 +- tests/scripts/test050-syncrepl-multimaster | 30 +- tests/scripts/test051-config-undo | 9 +- 463 files changed, 24632 insertions(+), 16338 deletions(-) create mode 100644 contrib/slapd-modules/addpartial/COPYRIGHT create mode 100644 contrib/slapd-modules/addpartial/LICENSE create mode 100644 contrib/slapd-modules/addpartial/Makefile create mode 100644 contrib/slapd-modules/addpartial/README create mode 100644 contrib/slapd-modules/addpartial/addpartial-overlay.c create mode 100644 doc/drafts/draft-haripriya-dynamicgroup-xx.txt create mode 100644 doc/drafts/draft-wahl-ldap-session-xx.txt rename doc/drafts/{draft-zeilenga-ldap-managedit-xx.txt => draft-zeilenga-ldap-relax.txt} (64%) delete mode 100644 doc/man/man5/slapd.replog.5 create mode 100644 doc/man/man5/slapo-constraint.5 create mode 100644 doc/man/man5/slapo-dyngroup.5 create mode 100644 doc/man/man5/slapo-memberof.5 delete mode 100644 doc/man/man8/slurpd.8 create mode 100644 doc/rfc/rfc5020.txt create mode 100644 libraries/libldap/stctrl.c delete mode 100644 servers/slapd/back-relay/config.c create mode 100644 servers/slapd/overlays/memberof.c delete mode 100644 servers/slapd/repl.c delete mode 100644 servers/slurpd/DESIGN delete mode 100644 servers/slurpd/Makefile.in delete mode 100644 servers/slurpd/NOTES delete mode 100644 servers/slurpd/admin.c delete mode 100644 servers/slurpd/args.c delete mode 100644 servers/slurpd/ch_malloc.c delete mode 100644 servers/slurpd/config.c delete mode 100644 servers/slurpd/fm.c delete mode 100644 servers/slurpd/globals.c delete mode 100644 servers/slurpd/globals.h delete mode 100644 servers/slurpd/ldap_op.c delete mode 100644 servers/slurpd/lock.c delete mode 100644 servers/slurpd/main.c delete mode 100644 servers/slurpd/nt_svc.c delete mode 100644 servers/slurpd/proto-slurp.h delete mode 100644 servers/slurpd/re.c delete mode 100644 servers/slurpd/reject.c delete mode 100644 servers/slurpd/replica.c delete mode 100644 servers/slurpd/replog.c delete mode 100644 servers/slurpd/ri.c delete mode 100644 servers/slurpd/rq.c delete mode 100644 servers/slurpd/sanity.c delete mode 100644 servers/slurpd/slurp.h delete mode 100644 servers/slurpd/st.c delete mode 100644 tests/data/slapd-repl-master.conf delete mode 100644 tests/data/slapd-repl-slave.conf delete mode 100755 tests/scripts/test007-replication diff --git a/COPYRIGHT b/COPYRIGHT index db69cf2d0e..fbfe5d4ed4 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -36,9 +36,11 @@ Public License. --- -Portions Copyright 1999-2005 Howard Y.H. Chu. -Portions Copyright 1999-2005 Symas Corporation. +Portions Copyright 1999-2007 Howard Y.H. Chu. +Portions Copyright 1999-2007 Symas Corporation. Portions Copyright 1998-2003 Hallvard B. Furuseth. +Portions Copyright 2007 Gavin Henry +Portions Copyright 2007 Suretec Systems All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README b/README index 612ad6c637..9a03a72ab1 100644 --- a/README +++ b/README @@ -21,10 +21,6 @@ REQUIRED SOFTWARE SLAPD: BDB and HDB backends require Sleepycat Berkeley DB 4.2 or later - SLURPD: - LTHREAD compatible thread package - [POSIX threads, Mach Cthreads, select others] - CLIENTS/CONTRIB ware: Depends on package. See per package README. diff --git a/build/config.guess b/build/config.guess index a55c277e84..f936d180ab 100755 --- a/build/config.guess +++ b/build/config.guess @@ -29,7 +29,7 @@ timestamp='2003-07-02-OpenLDAP' # configuration script generated by Autoconf, and is distributable # under the same distributions terms as OpenLDAP itself. -## Copyright 1998-2007 The OpenLDAP Foundation. +## Portions Copyright 1998-2007 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without diff --git a/build/config.sub b/build/config.sub index 0678b9d155..77792ff06d 100755 --- a/build/config.sub +++ b/build/config.sub @@ -34,7 +34,7 @@ timestamp='2003-07-04-OpenLDAP' # configuration script generated by Autoconf, and is distributable # under the same distributions terms as OpenLDAP itself. -## Copyright 1998-2007 The OpenLDAP Foundation. +## Portions Copyright 1998-2007 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without diff --git a/build/ltmain.sh b/build/ltmain.sh index be364aa8c8..21b86bbb4a 100755 --- a/build/ltmain.sh +++ b/build/ltmain.sh @@ -26,9 +26,9 @@ # This file is distributed with OpenLDAP Software, which contains a # configuration script generated by Autoconf, and is distributable -# under the same distributions terms as OpenLDAP inself. +# under the same distributions terms as OpenLDAP itself. -## Copyright 1998-2007 The OpenLDAP Foundation. +## Portions Copyright 1998-2007 The OpenLDAP Foundation. ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without diff --git a/build/openldap.m4 b/build/openldap.m4 index 5fa82a24e7..9f627b534c 100644 --- a/build/openldap.m4 +++ b/build/openldap.m4 @@ -91,6 +91,7 @@ EOF done rm -f conftest* ]) + test "$ol_cv_mkdep" = no && OL_MKDEP=":" else cc_cv_mkdep=yes OL_MKDEP_FLAGS="${MKDEP_FLAGS}" @@ -627,9 +628,9 @@ main() } #if (DB_VERSION_MAJOR > 3) || (DB_VERSION_MINOR >= 1) - rc = env->open( env, NULL, flags, 0 ); + rc = (env->open)( env, NULL, flags, 0 ); #else - rc = env->open( env, NULL, NULL, flags, 0 ); + rc = (env->open)( env, NULL, NULL, flags, 0 ); #endif if ( rc == 0 ) { @@ -736,152 +737,6 @@ fi ]) dnl dnl ==================================================================== -dnl Check if GDBM library exists -dnl Check for gdbm_open in standard libraries or -lgdbm -dnl -dnl defines ol_cv_lib_gdbm to 'yes' or '-lgdbm' or 'no' -dnl 'yes' implies gdbm_open is in $LIBS -dnl -dnl uses: -dnl AC_CHECK_FUNC(gdbm_open) -dnl AC_CHECK_LIB(gdbm,gdbm_open) -dnl -AC_DEFUN([OL_LIB_GDBM], -[AC_CACHE_CHECK(for GDBM library, [ol_cv_lib_gdbm], -[ ol_LIBS="$LIBS" - AC_CHECK_FUNC(gdbm_open,[ol_cv_lib_gdbm=yes], [ - AC_CHECK_LIB(gdbm,gdbm_open,[ol_cv_lib_gdbm=-lgdbm],[ol_cv_lib_gdbm=no]) - ]) - LIBS="$ol_LIBS" -]) -])dnl -dnl -dnl -------------------------------------------------------------------- -dnl Check if GDBM exists -dnl -dnl defines ol_cv_gdbm to 'yes' or 'no' -dnl -dnl uses: -dnl OL_LIB_GDBM -dnl AC_CHECK_HEADERS(gdbm.h) -dnl -AC_DEFUN([OL_GDBM], -[AC_REQUIRE([OL_LIB_GDBM]) - AC_CHECK_HEADERS(gdbm.h) - AC_CACHE_CHECK(for db, [ol_cv_gdbm], [ - if test $ol_cv_lib_gdbm = no || test $ac_cv_header_gdbm_h = no ; then - ol_cv_gdbm=no - else - ol_cv_gdbm=yes - fi -]) - if test $ol_cv_gdbm = yes ; then - AC_DEFINE(HAVE_GDBM,1, [define if GNU DBM is available]) - fi -])dnl -dnl -dnl ==================================================================== -dnl Check if MDBM library exists -dnl Check for mdbm_open in standard libraries or -lmdbm -dnl -dnl defines ol_cv_lib_mdbm to 'yes' or '-lmdbm' or 'no' -dnl 'yes' implies mdbm_open is in $LIBS -dnl -dnl uses: -dnl AC_CHECK_FUNC(mdbm_set_chain) -dnl AC_CHECK_LIB(mdbm,mdbm_set_chain) -dnl -AC_DEFUN([OL_LIB_MDBM], -[AC_CACHE_CHECK(for MDBM library, [ol_cv_lib_mdbm], -[ ol_LIBS="$LIBS" - AC_CHECK_FUNC(mdbm_set_chain,[ol_cv_lib_mdbm=yes], [ - AC_CHECK_LIB(mdbm,mdbm_set_chain,[ol_cv_lib_mdbm=-lmdbm],[ol_cv_lib_mdbm=no]) - ]) - LIBS="$ol_LIBS" -]) -])dnl -dnl -dnl -------------------------------------------------------------------- -dnl Check if MDBM exists -dnl -dnl defines ol_cv_mdbm to 'yes' or 'no' -dnl -dnl uses: -dnl OL_LIB_MDBM -dnl AC_CHECK_HEADERS(mdbm.h) -dnl -AC_DEFUN([OL_MDBM], -[AC_REQUIRE([OL_LIB_MDBM]) - AC_CHECK_HEADERS(mdbm.h) - AC_CACHE_CHECK(for db, [ol_cv_mdbm], [ - if test $ol_cv_lib_mdbm = no || test $ac_cv_header_mdbm_h = no ; then - ol_cv_mdbm=no - else - ol_cv_mdbm=yes - fi -]) - if test $ol_cv_mdbm = yes ; then - AC_DEFINE(HAVE_MDBM,1, [define if MDBM is available]) - fi -])dnl -dnl -dnl ==================================================================== -dnl Check if NDBM library exists -dnl Check for dbm_open in standard libraries or -lndbm or -ldbm -dnl -dnl defines ol_cv_lib_ndbm to 'yes' or '-lndbm' or -ldbm or 'no' -dnl 'yes' implies ndbm_open is in $LIBS -dnl -dnl uses: -dnl AC_CHECK_FUNC(dbm_open) -dnl AC_CHECK_LIB(ndbm,dbm_open) -dnl AC_CHECK_LIB(dbm,dbm_open) -dnl -dnl restrictions: -dnl should also check SVR4 case: dbm_open() in -lucb but that -dnl would requiring dealing with -L/usr/ucblib -dnl -AC_DEFUN([OL_LIB_NDBM], -[AC_CACHE_CHECK(for NDBM library, [ol_cv_lib_ndbm], -[ ol_LIBS="$LIBS" - AC_CHECK_FUNC(dbm_open,[ol_cv_lib_ndbm=yes], [ - AC_CHECK_LIB(ndbm,dbm_open,[ol_cv_lib_ndbm=-lndbm], [ - AC_CHECK_LIB(dbm,dbm_open,[ol_cv_lib_ndbm=-ldbm], - [ol_cv_lib_ndbm=no])dnl - ]) - ]) - LIBS="$ol_LIBS" -]) -])dnl -dnl -dnl -------------------------------------------------------------------- -dnl Check if NDBM exists -dnl -dnl defines ol_cv_ndbm to 'yes' or 'no' -dnl -dnl uses: -dnl OL_LIB_NDBM -dnl AC_CHECK_HEADERS(ndbm.h) -dnl -dnl restrictions: -dnl Doesn't handle SVR4 case (see above) -dnl -AC_DEFUN([OL_NDBM], -[AC_REQUIRE([OL_LIB_NDBM]) - AC_CHECK_HEADERS(ndbm.h) - AC_CACHE_CHECK(for db, [ol_cv_ndbm], [ - if test $ol_cv_lib_ndbm = no || test $ac_cv_header_ndbm_h = no ; then - ol_cv_ndbm=no - else - ol_cv_ndbm=yes - fi -]) - if test $ol_cv_ndbm = yes ; then - AC_DEFINE(HAVE_NDBM,1, [define if NDBM is available]) - fi -])dnl -dnl -dnl ==================================================================== dnl Check POSIX Thread version dnl dnl defines ol_cv_pthread_version to 4, 5, 6, 7, 8, 10, depending on the diff --git a/build/top.mk b/build/top.mk index d63fd33776..3b81f63d9d 100644 --- a/build/top.mk +++ b/build/top.mk @@ -170,10 +170,8 @@ LDAP_LIBLUTIL_A = $(LDAP_LIBDIR)/liblutil/liblutil.a LDAP_L = $(LDAP_LIBLUTIL_A) \ $(LDAP_LIBLDAP_LA) $(LDAP_LIBLBER_LA) -SLURPD_L = $(LDAP_LIBLUTIL_A) \ - $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA) SLAPD_L = $(LDAP_LIBLUNICODE_A) $(LDAP_LIBREWRITE_A) \ - $(SLURPD_L) + $(LDAP_LIBLUTIL_A) $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA) WRAP_LIBS = @WRAP_LIBS@ # AutoConfig generated @@ -202,7 +200,6 @@ SLAPD_SQL_INCLUDES = @SLAPD_SQL_INCLUDES@ SLAPD_SQL_LIBS = @SLAPD_SQL_LIBS@ SLAPD_LIBS = @SLAPD_LIBS@ @SLAPD_PERL_LDFLAGS@ @SLAPD_SQL_LDFLAGS@ @SLAPD_SQL_LIBS@ @SLAPD_SLP_LIBS@ @SLAPD_GMP_LIBS@ $(ICU_LIBS) -SLURPD_LIBS = @SLURPD_LIBS@ # Our Defaults CC = $(AC_CC) diff --git a/clients/tools/common.c b/clients/tools/common.c index fbacf5ad29..bffbf121d0 100644 --- a/clients/tools/common.c +++ b/clients/tools/common.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_CYRUS_SASL #ifdef HAVE_SASL_SASL_H @@ -113,6 +114,13 @@ int chaining = 0; static int chainingResolve = -1; static int chainingContinuation = -1; #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ +#ifdef LDAP_CONTROL_X_SESSION_TRACKING +static int sessionTracking = 0; +struct berval stValue; +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + +LDAPControl *unknown_ctrls = NULL; +int unknown_ctrls_num = 0; /* options */ struct timeval nettimeout = { -1 , 0 }; @@ -144,6 +152,53 @@ static struct tool_ctrls_t { static int gotintr; static int abcan; + +#ifdef LDAP_CONTROL_X_SESSION_TRACKING +static int +st_value( LDAP *ld, struct berval *value ) +{ + char *ip = NULL, *name = NULL; + struct berval id = { 0 }; + char namebuf[ MAXHOSTNAMELEN ]; + + if ( gethostname( namebuf, sizeof( namebuf ) ) == 0 ) { + struct hostent *h; + struct in_addr addr; + + name = namebuf; + + h = gethostbyname( name ); + if ( h != NULL ) { + AC_MEMCPY( &addr, h->h_addr, sizeof( addr ) ); + ip = inet_ntoa( addr ); + } + } + +#ifdef HAVE_CYRUS_SASL + if ( sasl_authz_id != NULL ) { + ber_str2bv( sasl_authz_id, 0, 0, &id ); + + } else if ( sasl_authc_id != NULL ) { + ber_str2bv( sasl_authc_id, 0, 0, &id ); + + } else +#endif /* HAVE_CYRUS_SASL */ + if ( binddn != NULL ) { + ber_str2bv( binddn, 0, 0, &id ); + } + + if ( ldap_create_session_tracking_value( ld, + ip, name, LDAP_CONTROL_X_SESSION_TRACKING_USERNAME, + &id, &stValue ) ) + { + fprintf( stderr, _("Session tracking control encoding error!\n") ); + return -1; + } + + return 0; +} +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + RETSIGTYPE do_sig( int sig ) { @@ -175,7 +230,6 @@ tool_common_usage( void ) { static const char *const descriptions[] = { N_(" -c continuous operation mode (do not stop on errors)\n"), -N_(" -C chase referrals (anonymously)\n"), N_(" -d level set LDAP debugging level to `level'\n"), N_(" -D binddn bind DN\n"), N_(" -e [!][=] general extensions (! indicates criticality)\n") @@ -199,15 +253,16 @@ N_(" ppolicy\n") #endif N_(" [!]postread[=] (a comma-separated attribute list)\n") N_(" [!]preread[=] (a comma-separated attribute list)\n") -#ifdef LDAP_DEVEL N_(" [!]relax\n") -#endif +#ifdef LDAP_CONTROL_X_SESSION_TRACKING +N_(" [!]sessiontracking\n") +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ N_(" abandon, cancel, ignore (SIGINT sends abandon/cancel,\n" " or ignores response; if critical, doesn't wait for SIGINT.\n" " not really controls)\n") N_(" -f file read operations from `file'\n"), N_(" -h host LDAP server\n"), -N_(" -H URI LDAP Uniform Resource Indentifier(s)\n"), +N_(" -H URI LDAP Uniform Resource Identifier(s)\n"), N_(" -I use SASL Interactive mode\n"), N_(" -M enable Manage DSA IT control (-MM to make critical)\n"), N_(" -n show what would be done but don't actually do it\n"), @@ -215,7 +270,7 @@ N_(" -O props SASL security properties\n"), N_(" -o [= (in seconds, or \"none\" or \"max\")\n"), N_(" -p port port on LDAP server\n"), -N_(" -P version procotol version (default: 3)\n"), +N_(" -P version protocol version (default: 3)\n"), N_(" -Q use SASL Quiet mode\n"), N_(" -R realm SASL realm\n"), N_(" -U authcid SASL authentication identity\n"), @@ -299,7 +354,7 @@ tool_args( int argc, char **argv ) } binddn = ber_strdup( optarg ); break; - case 'e': /* general extensions (controls and such) */ + case 'e': /* general extensions (controls and such) */ /* should be extended to support comma separated list of * [!]key[=value] parameters, e.g. -e !foo,bar=567 */ @@ -520,6 +575,55 @@ tool_args( int argc, char **argv ) gotintr = abcan; } +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + } else if ( strcasecmp( control, "sessiontracking" ) == 0 ) { + if ( sessionTracking ) { + fprintf( stderr, "%s: session tracking can be only specified once\n", prog ); + exit( EXIT_FAILURE ); + } + sessionTracking = 1; +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + + } else if ( tool_is_oid( control ) ) { + LDAPControl *tmpctrls, ctrl; + + tmpctrls = (LDAPControl *)realloc( unknown_ctrls, + (unknown_ctrls_num + 1)*sizeof( LDAPControl ) ); + if ( tmpctrls == NULL ) { + fprintf( stderr, "%s: no memory?\n", prog ); + exit( EXIT_FAILURE ); + } + unknown_ctrls = tmpctrls; + ctrl.ldctl_oid = control; + ctrl.ldctl_value.bv_val = NULL; + ctrl.ldctl_value.bv_len = 0; + ctrl.ldctl_iscritical = crit; + + if ( cvalue != NULL ) { + struct berval bv; + size_t len = strlen( cvalue ); + int retcode; + + bv.bv_len = LUTIL_BASE64_DECODE_LEN( len ); + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + retcode = lutil_b64_pton( cvalue, + (unsigned char *)bv.bv_val, + bv.bv_len ); + + if ( retcode == -1 || retcode > bv.bv_len ) { + fprintf( stderr, "Unable to parse value of general control %s\n", + control ); + usage(); + } + + bv.bv_len = retcode; + ctrl.ldctl_value = bv; + } + + unknown_ctrls[ unknown_ctrls_num ] = ctrl; + unknown_ctrls_num++; + } else { fprintf( stderr, "Invalid general control name: %s\n", control ); @@ -893,6 +997,9 @@ tool_args( int argc, char **argv ) #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR chaining || #endif +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + sessionTracking || +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ noop || ppolicy || preread || postread ) { fprintf( stderr, "%s: -e/-M incompatible with LDAPv2\n", prog ); @@ -957,6 +1064,137 @@ tool_conn_setup( int dont, void (*private_setup)( LDAP * ) ) url.lud_scope = LDAP_SCOPE_DEFAULT; ldapuri = ldap_url_desc2str( &url ); + + } else if ( ldapuri != NULL ) { + LDAPURLDesc *ludlist, **ludp; + char **urls = NULL; + int nurls = 0; + + rc = ldap_url_parselist( &ludlist, ldapuri ); + if ( rc != LDAP_URL_SUCCESS ) { + fprintf( stderr, + "Could not parse LDAP URI(s)=%s (%d)\n", + ldapuri, rc ); + exit( EXIT_FAILURE ); + } + + for ( ludp = &ludlist; *ludp != NULL; ) { + LDAPURLDesc *lud = *ludp; + char **tmp; + + if ( lud->lud_dn != NULL && lud->lud_dn[ 0 ] != '\0' && + ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) ) + { + /* if no host but a DN is provided, + * use DNS SRV to gather the host list + * and turn it into a list of URIs + * using the scheme provided */ + char *domain = NULL, + *hostlist = NULL, + **hosts = NULL; + int i, + len_proto = strlen( lud->lud_scheme ); + + if ( ldap_dn2domain( lud->lud_dn, &domain ) + || domain == NULL ) + { + fprintf( stderr, + "DNS SRV: Could not turn " + "DN=\"%s\" into a domain\n", + lud->lud_dn ); + goto dnssrv_free; + } + + rc = ldap_domain2hostlist( domain, &hostlist ); + if ( rc ) { + fprintf( stderr, + "DNS SRV: Could not turn " + "domain=%s into a hostlist\n", + domain ); + goto dnssrv_free; + } + + hosts = ldap_str2charray( hostlist, " " ); + if ( hosts == NULL ) { + fprintf( stderr, + "DNS SRV: Could not parse " + "hostlist=\"%s\"\n", + hostlist ); + goto dnssrv_free; + } + + for ( i = 0; hosts[ i ] != NULL; i++ ) + /* count'em */ ; + + tmp = (char **)realloc( urls, sizeof( char * ) * ( nurls + i + 1 ) ); + if ( tmp == NULL ) { + fprintf( stderr, + "DNS SRV: out of memory?\n" ); + goto dnssrv_free; + } + urls = tmp; + urls[ nurls ] = NULL; + + for ( i = 0; hosts[ i ] != NULL; i++ ) { + size_t len = len_proto + + STRLENOF( "://" ) + + strlen( hosts[ i ] ) + + 1; + + urls[ nurls + i + 1 ] = NULL; + urls[ nurls + i ] = (char *)malloc( sizeof( char ) * len ); + if ( urls[ nurls + i ] == NULL ) { + fprintf( stderr, + "DNS SRV: out of memory?\n" ); + goto dnssrv_free; + } + + snprintf( urls[ nurls + i ], len, "%s://%s", + lud->lud_scheme, hosts[ i ] ); + } + nurls += i; + +dnssrv_free:; + ber_memvfree( (void **)hosts ); + ber_memfree( hostlist ); + ber_memfree( domain ); + + } else { + tmp = (char **)realloc( urls, sizeof( char * ) * ( nurls + 2 ) ); + if ( tmp == NULL ) { + fprintf( stderr, + "DNS SRV: out of memory?\n" ); + break; + } + urls = tmp; + urls[ nurls + 1 ] = NULL; + + urls[ nurls ] = ldap_url_desc2str( lud ); + if ( urls[ nurls ] == NULL ) { + fprintf( stderr, + "DNS SRV: out of memory?\n" ); + break; + } + nurls++; + } + + *ludp = lud->lud_next; + + lud->lud_next = NULL; + ldap_free_urldesc( lud ); + } + + if ( ludlist != NULL ) { + ldap_free_urllist( ludlist ); + exit( EXIT_FAILURE ); + + } else if ( urls == NULL ) { + exit( EXIT_FAILURE ); + } + + ldap_memfree( ldapuri ); + ldapuri = ldap_charray2str( urls, " " ); + ber_memvfree( (void **)urls ); } if ( verbose ) { @@ -1019,21 +1257,41 @@ void tool_bind( LDAP *ld ) { LDAPControl **sctrlsp = NULL; - LDAPControl *sctrls[2]; + LDAPControl *sctrls[3]; + LDAPControl sctrl[3]; int nsctrls = 0; #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST - LDAPControl c; if ( ppolicy ) { + LDAPControl c; c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST; c.ldctl_value.bv_val = NULL; c.ldctl_value.bv_len = 0; c.ldctl_iscritical = 0; - sctrls[nsctrls] = &c; + sctrl[nsctrls] = c; + sctrls[nsctrls] = &sctrl[nsctrls]; sctrls[++nsctrls] = NULL; } #endif +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + if ( sessionTracking ) { + LDAPControl c; + + if (stValue.bv_val == NULL && st_value( ld, &stValue ) ) { + exit( EXIT_FAILURE ); + } + + c.ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING; + c.ldctl_iscritical = 0; + ber_dupbv( &c.ldctl_value, &stValue ); + + sctrl[nsctrls] = c; + sctrls[nsctrls] = &sctrl[nsctrls]; + sctrls[++nsctrls] = NULL; + } +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + if ( nsctrls ) { sctrlsp = sctrls; } @@ -1108,7 +1366,7 @@ tool_bind( LDAP *ld ) rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs, &ctrls, 1 ); if ( rc != LDAP_SUCCESS ) { - tool_perror( "ldap_bind parse result", rc, NULL, NULL, NULL, NULL ); + tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs ); exit( LDAP_LOCAL_ERROR ); } @@ -1118,8 +1376,8 @@ tool_bind( LDAP *ld ) int expire, grace, len = 0; LDAPPasswordPolicyError pErr = -1; - ctrl = ldap_find_control( LDAP_CONTROL_PASSWORDPOLICYRESPONSE, - ctrls ); + ctrl = ldap_control_find( LDAP_CONTROL_PASSWORDPOLICYRESPONSE, + ctrls, NULL ); if ( ctrl && ldap_parse_passwordpolicy_control( ld, ctrl, &expire, &grace, &pErr ) == LDAP_SUCCESS ) @@ -1182,7 +1440,7 @@ void tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) { int i = 0, j, crit = 0, err; - LDAPControl c[10], **ctrls; + LDAPControl c[16], **ctrls; if ( ! ( assertctl || authzid @@ -1192,17 +1450,24 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) || manageDIT || manageDSAit || noop +#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST + || ppolicy +#endif || preread || postread #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR || chaining #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ - || count ) ) +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + || sessionTracking +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + || count + || unknown_ctrls_num ) ) { return; } - ctrls = (LDAPControl**) malloc(sizeof(c) + (count+1)*sizeof(LDAPControl*)); + ctrls = (LDAPControl**) malloc(sizeof(c) + (count + unknown_ctrls_num + 1)*sizeof(LDAPControl*)); if ( ctrls == NULL ) { fprintf( stderr, "No memory\n" ); exit( EXIT_FAILURE ); @@ -1294,6 +1559,16 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) i++; } +#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST + if ( ppolicy ) { + c[i].ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST; + BER_BVZERO( &c[i].ldctl_value ); + c[i].ldctl_iscritical = 0; + ctrls[i] = &c[i]; + i++; + } +#endif + if ( preread ) { char berbuf[LBER_ELEMENT_SIZEOF]; BerElement *ber = (BerElement *)berbuf; @@ -1400,9 +1675,27 @@ tool_server_controls( LDAP *ld, LDAPControl *extra_c, int count ) } #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + if ( sessionTracking ) { + if ( stValue.bv_val == NULL && st_value( ld, &stValue ) ) { + exit( EXIT_FAILURE ); + } + + c[i].ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING; + c[i].ldctl_iscritical = 0; + ber_dupbv( &c[i].ldctl_value, &stValue ); + + ctrls[i] = &c[i]; + i++; + } +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + while ( count-- ) { ctrls[i++] = extra_c++; } + for ( count = 0; count < unknown_ctrls_num; count++ ) { + ctrls[i++] = &unknown_ctrls[count]; + } ctrls[i] = NULL; err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls ); @@ -1594,7 +1887,8 @@ print_ppolicy( LDAP *ld, LDAPControl *ctrl ) if ( pperr != PP_noError ) { ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), - "%serror=%s", ptr == buf ? "" : " ", + "%serror=%d (%s)", ptr == buf ? "" : " ", + pperr, ldap_passwordpolicy_err2txt( pperr ) ); } @@ -1620,6 +1914,13 @@ void tool_print_ctrls( char *str; int j; + /* FIXME: there might be cases where a control has NULL OID; + * this makes little sense, especially when returned by the + * server, but libldap happily allows it */ + if ( ctrls[i]->ldctl_oid == NULL ) { + continue; + } + len = ldif ? 2 : 0; len += strlen( ctrls[i]->ldctl_oid ); @@ -1628,7 +1929,7 @@ void tool_print_ctrls( ? sizeof("true") : sizeof("false"); /* convert to base64 */ - if ( ctrls[i]->ldctl_value.bv_len ) { + if ( !BER_BVISNULL( &ctrls[i]->ldctl_value ) ) { b64.bv_len = LUTIL_BASE64_ENCODE_LEN( ctrls[i]->ldctl_value.bv_len ) + 1; b64.bv_val = ber_memalloc( b64.bv_len + 1 ); diff --git a/clients/tools/ldapcompare.c b/clients/tools/ldapcompare.c index 47753525e1..18f9179476 100644 --- a/clients/tools/ldapcompare.c +++ b/clients/tools/ldapcompare.c @@ -288,6 +288,7 @@ static int docompare( char *matcheddn; char *text; char **refs; + LDAPControl **ctrls = NULL; if ( dont ) { return LDAP_SUCCESS; @@ -320,7 +321,7 @@ static int docompare( } } - rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 ); + rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n", @@ -350,10 +351,6 @@ static int docompare( } } - ber_memfree( text ); - ber_memfree( matcheddn ); - ber_memvfree( (void **) refs ); - /* if we were told to be quiet, use the return value. */ if ( !quiet ) { if ( code == LDAP_COMPARE_TRUE ) { @@ -365,6 +362,15 @@ static int docompare( } } + if ( ctrls ) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } + + ber_memfree( text ); + ber_memfree( matcheddn ); + ber_memvfree( (void **) refs ); + return( code ); } diff --git a/clients/tools/ldapdelete.c b/clients/tools/ldapdelete.c index 8133a2d3a0..635db793fa 100644 --- a/clients/tools/ldapdelete.c +++ b/clients/tools/ldapdelete.c @@ -210,6 +210,7 @@ static int dodelete( int id; int rc, code; char *matcheddn = NULL, *text = NULL, **refs = NULL; + LDAPControl **ctrls = NULL; LDAPMessage *res; if ( verbose ) { @@ -254,7 +255,7 @@ static int dodelete( } } - rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 ); + rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n", @@ -286,6 +287,11 @@ static int dodelete( } } + if (ctrls) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } + ber_memfree( text ); ber_memfree( matcheddn ); ber_memvfree( (void **) refs ); diff --git a/clients/tools/ldapexop.c b/clients/tools/ldapexop.c index 59632de3c2..6de7ec2bd0 100644 --- a/clients/tools/ldapexop.c +++ b/clients/tools/ldapexop.c @@ -66,11 +66,11 @@ int main( int argc, char *argv[] ) { int rc; - char *user = NULL; LDAP *ld = NULL; char *matcheddn = NULL, *text = NULL, **refs = NULL; + LDAPControl **ctrls = NULL; int id, code; LDAPMessage *res; @@ -104,18 +104,6 @@ main( int argc, char *argv[] ) argc -= optind; if ( strcasecmp( argv[ 0 ], "whoami" ) == 0 ) { - switch ( argc ) { - case 2: - user = argv[ 1 ]; - - case 1: - break; - - default: - fprintf( stderr, "need [user]\n\n" ); - usage(); - } - tool_server_controls( ld, NULL, 0 ); rc = ldap_whoami( ld, NULL, NULL, &id ); @@ -253,7 +241,7 @@ main( int argc, char *argv[] ) } rc = ldap_parse_result( ld, res, - &code, &matcheddn, &text, &refs, NULL, 0 ); + &code, &matcheddn, &text, &refs, &ctrls, 0 ); if ( rc == LDAP_SUCCESS ) { rc = code; } @@ -358,6 +346,11 @@ main( int argc, char *argv[] ) } } + if (ctrls) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } + ber_memfree( text ); ber_memfree( matcheddn ); ber_memvfree( (void **) refs ); diff --git a/clients/tools/ldapmodify.c b/clients/tools/ldapmodify.c index ee59c0f7dc..dac9efcd82 100644 --- a/clients/tools/ldapmodify.c +++ b/clients/tools/ldapmodify.c @@ -92,7 +92,6 @@ static struct berval BV_MODOPADD = BER_BVC("add"); static struct berval BV_MODOPREPLACE = BER_BVC("replace"); static struct berval BV_MODOPDELETE = BER_BVC("delete"); static struct berval BV_MODOPINCREMENT = BER_BVC("increment"); -static struct berval BV_MODSEP = BER_BVC("-"); static struct berval BV_NEWRDN = BER_BVC("newrdn"); static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn"); static struct berval BV_NEWSUP = BER_BVC("newsuperior"); @@ -372,9 +371,9 @@ main( int argc, char **argv ) fprintf( rejfp, "\n%s\n", rejbuf ); } - if (rejfp) free( rejbuf ); + if (rejfp) ber_memfree( rejbuf ); } - free( rbuf ); + ber_memfree( rbuf ); #ifdef LDAP_X_TXN if( retval == 0 && txn ) { @@ -1296,7 +1295,7 @@ static int process_response( if ( matched ) ldap_memfree( matched ); if ( text ) ber_memvfree( (void **)refs ); - if ( ctrls != NULL ) { + if ( ctrls ) { tool_print_ctrls( ld, ctrls ); ldap_controls_free( ctrls ); } diff --git a/clients/tools/ldapmodrdn.c b/clients/tools/ldapmodrdn.c index 9b03471f47..477b74e365 100644 --- a/clients/tools/ldapmodrdn.c +++ b/clients/tools/ldapmodrdn.c @@ -241,6 +241,7 @@ static int domodrdn( { int rc, code, id; char *matcheddn=NULL, *text=NULL, **refs=NULL; + LDAPControl **ctrls = NULL; LDAPMessage *res; if ( verbose ) { @@ -284,7 +285,7 @@ static int domodrdn( } } - rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 ); + rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n", @@ -314,6 +315,11 @@ static int domodrdn( } } + if (ctrls) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } + ber_memfree( text ); ber_memfree( matcheddn ); ber_memvfree( (void **) refs ); diff --git a/clients/tools/ldappasswd.c b/clients/tools/ldappasswd.c index 7645e55e0a..5d676e399e 100644 --- a/clients/tools/ldappasswd.c +++ b/clients/tools/ldappasswd.c @@ -177,6 +177,7 @@ main( int argc, char *argv[] ) char *matcheddn = NULL, *text = NULL, **refs = NULL; char *retoid = NULL; struct berval *retdata = NULL; + LDAPControl **ctrls = NULL; tool_init( TOOL_PASSWD ); prog = lutil_progname( "ldappasswd", argc, argv ); @@ -310,6 +311,8 @@ main( int argc, char *argv[] ) goto done; } + tool_server_controls( ld, NULL, 0); + rc = ldap_extended_operation( ld, LDAP_EXOP_MODIFY_PASSWD, bv.bv_val ? &bv : NULL, NULL, NULL, &id ); @@ -344,7 +347,7 @@ main( int argc, char *argv[] ) } rc = ldap_parse_result( ld, res, - &code, &matcheddn, &text, &refs, NULL, 0 ); + &code, &matcheddn, &text, &refs, &ctrls, 0 ); if( rc != LDAP_SUCCESS ) { tool_perror( "ldap_parse_result", rc, NULL, NULL, NULL, NULL ); rc = EXIT_FAILURE; @@ -381,12 +384,15 @@ main( int argc, char *argv[] ) ber_free( ber, 1 ); - } else if ( newpw.bv_val == NULL ) { + } else if ( code == LDAP_SUCCESS && newpw.bv_val == NULL ) { tool_perror( "ldap_parse_extended_result", LDAP_DECODING_ERROR, " new password expected", NULL, NULL, NULL ); } - if( verbose || code != LDAP_SUCCESS || matcheddn || text || refs ) { +skip: + if( verbose || code != LDAP_SUCCESS || + matcheddn || text || refs || ctrls ) + { printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code ); if( text && *text ) { @@ -403,6 +409,11 @@ main( int argc, char *argv[] ) printf(_("Referral: %s\n"), refs[i] ); } } + + if( ctrls ) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } } ber_memfree( text ); @@ -411,9 +422,6 @@ main( int argc, char *argv[] ) ber_memfree( retoid ); ber_bvfree( retdata ); - rc = ldap_search_s( ld, binddn, LDAP_SCOPE_BASE, "(objectclass=*)", - NULL, 0, &res ); - rc = ( code == LDAP_SUCCESS ) ? EXIT_SUCCESS : EXIT_FAILURE; done: diff --git a/clients/tools/ldapwhoami.c b/clients/tools/ldapwhoami.c index 7d20097848..08ca1414de 100644 --- a/clients/tools/ldapwhoami.c +++ b/clients/tools/ldapwhoami.c @@ -109,15 +109,13 @@ int main( int argc, char *argv[] ) { int rc; - char *user = NULL; - LDAP *ld = NULL; - char *matcheddn = NULL, *text = NULL, **refs = NULL; char *retoid = NULL; struct berval *retdata = NULL; int id, code = 0; LDAPMessage *res; + LDAPControl **ctrls = NULL; tool_init( TOOL_WHOAMI ); prog = lutil_progname( "ldapwhoami", argc, argv ); @@ -127,12 +125,8 @@ main( int argc, char *argv[] ) tool_args( argc, argv ); - if( argc - optind > 1 ) { + if( argc - optind > 0 ) { usage(); - } else if ( argc - optind == 1 ) { - user = strdup( argv[optind] ); - } else { - user = NULL; } if ( pw_file || want_bindpw ) { @@ -159,7 +153,7 @@ main( int argc, char *argv[] ) rc = ldap_whoami( ld, NULL, NULL, &id ); if( rc != LDAP_SUCCESS ) { - tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL ); + tool_perror( "ldap_whoami", rc, NULL, NULL, NULL, NULL ); rc = EXIT_FAILURE; goto skip; } @@ -186,7 +180,7 @@ main( int argc, char *argv[] ) } rc = ldap_parse_result( ld, res, - &code, &matcheddn, &text, &refs, NULL, 0 ); + &code, &matcheddn, &text, &refs, &ctrls, 0 ); if ( rc == LDAP_SUCCESS ) { rc = code; @@ -214,7 +208,10 @@ main( int argc, char *argv[] ) } } - if( verbose || ( code != LDAP_SUCCESS ) || matcheddn || text || refs ) { +skip: + if ( verbose || ( code != LDAP_SUCCESS ) || + matcheddn || text || refs || ctrls ) + { printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code ); if( text && *text ) { @@ -231,6 +228,11 @@ main( int argc, char *argv[] ) printf(_("Referral: %s\n"), refs[i] ); } } + + if (ctrls) { + tool_print_ctrls( ld, ctrls ); + ldap_controls_free( ctrls ); + } } ber_memfree( text ); @@ -239,7 +241,6 @@ main( int argc, char *argv[] ) ber_memfree( retoid ); ber_bvfree( retdata ); -skip: /* disconnect from server */ tool_unbind( ld ); tool_destroy(); diff --git a/configure b/configure index 204042d757..ee0e248313 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.631.2.4 2006/10/19 20:06:32 kurt Exp . +# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.658 2007/07/02 13:15:31 hallvard Exp . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # @@ -465,7 +465,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar OPENLDAP_LIBRELEASE OPENLDAP_LIBVERSION OPENLDAP_RELEASE_DATE top_builddir ldap_subdir CC AR CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO ac_ct_AR RANLIB ac_ct_RANLIB DLLTOOL ac_ct_DLLTOOL AS ac_ct_AS OBJDUMP ac_ct_OBJDUMP CPP LIBTOOL PERLBIN OL_MKDEP OL_MKDEP_FLAGS LTSTATIC LIBOBJS LIBSRCS PLAT WITH_SASL WITH_TLS WITH_MODULES_ENABLED WITH_ACI_ENABLED BUILD_THREAD BUILD_LIBS_DYNAMIC BUILD_SLAPD BUILD_SLAPI SLAPD_SLAPI_DEPEND BUILD_BDB BUILD_DNSSRV BUILD_HDB BUILD_LDAP BUILD_META BUILD_MONITOR BUILD_NULL BUILD_PASSWD BUILD_RELAY BUILD_PERL BUILD_SHELL BUILD_SQL BUILD_ACCESSLOG BUILD_AUDITLOG BUILD_CONSTRAINT BUILD_DDS BUILD_DENYOP BUILD_DYNGROUP BUILD_DYNLIST BUILD_LASTMOD BUILD_PPOLICY BUILD_PROXYCACHE BUILD_REFINT BUILD_RETCODE BUILD_RWM BUILD_SEQMOD BUILD_SYNCPROV BUILD_TRANSLUCENT BUILD_UNIQUE BUILD_VALSORT BUILD_SLURPD LDAP_LIBS SLAPD_LIBS SLURPD_LIBS BDB_LIBS LTHREAD_LIBS LUTIL_LIBS WRAP_LIBS SLAPD_MODULES_CPPFLAGS SLAPD_MODULES_LDFLAGS SLAPD_NO_STATIC SLAPD_STATIC_BACKENDS SLAPD_DYNAMIC_BACKENDS SLAPD_STATIC_OVERLAYS SLAPD_DYNAMIC_OVERLAYS PERL_CPPFLAGS SLAPD_PERL_LDFLAGS MOD_PERL_LDFLAGS KRB4_LIBS KRB5_LIBS SASL_LIBS TLS_LIBS MODULES_LIBS SLAPI_LIBS LIBSLAPI LIBSLAPITOOLS AUTH_LIBS ICU_LIBS SLAPD_SLP_LIBS SLAPD_GMP_LIBS SLAPD_SQL_LDFLAGS SLAPD_SQL_LIBS SLAPD_SQL_INCLUDES LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar OPENLDAP_LIBRELEASE OPENLDAP_LIBVERSION OPENLDAP_RELEASE_DATE top_builddir ldap_subdir CC AR CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO ac_ct_AR RANLIB ac_ct_RANLIB DLLTOOL ac_ct_DLLTOOL AS ac_ct_AS OBJDUMP ac_ct_OBJDUMP CPP LIBTOOL PERLBIN OL_MKDEP OL_MKDEP_FLAGS LTSTATIC LIBOBJS LIBSRCS PLAT WITH_SASL WITH_TLS WITH_MODULES_ENABLED WITH_ACI_ENABLED BUILD_THREAD BUILD_LIBS_DYNAMIC BUILD_SLAPD BUILD_SLAPI SLAPD_SLAPI_DEPEND BUILD_BDB BUILD_DNSSRV BUILD_HDB BUILD_LDAP BUILD_META BUILD_MONITOR BUILD_NULL BUILD_PASSWD BUILD_RELAY BUILD_PERL BUILD_SHELL BUILD_SQL BUILD_ACCESSLOG BUILD_AUDITLOG BUILD_CONSTRAINT BUILD_DDS BUILD_DENYOP BUILD_DYNGROUP BUILD_DYNLIST BUILD_LASTMOD BUILD_PPOLICY BUILD_PROXYCACHE BUILD_REFINT BUILD_RETCODE BUILD_RWM BUILD_SEQMOD BUILD_SYNCPROV BUILD_TRANSLUCENT BUILD_UNIQUE BUILD_VALSORT LDAP_LIBS SLAPD_LIBS BDB_LIBS LTHREAD_LIBS LUTIL_LIBS WRAP_LIBS SLAPD_MODULES_CPPFLAGS SLAPD_MODULES_LDFLAGS SLAPD_NO_STATIC SLAPD_STATIC_BACKENDS SLAPD_DYNAMIC_BACKENDS SLAPD_STATIC_OVERLAYS SLAPD_DYNAMIC_OVERLAYS PERL_CPPFLAGS SLAPD_PERL_LDFLAGS MOD_PERL_LDFLAGS KRB4_LIBS KRB5_LIBS SASL_LIBS TLS_LIBS MODULES_LIBS SLAPI_LIBS LIBSLAPI LIBSLAPITOOLS AUTH_LIBS ICU_LIBS SLAPD_SLP_LIBS SLAPD_GMP_LIBS SLAPD_SQL_LDFLAGS SLAPD_SQL_LIBS SLAPD_SQL_INCLUDES LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -1051,6 +1051,7 @@ SLAPD Overlay Options: --enable-dds Dynamic Directory Services overlay no|yes|mod [no] --enable-dyngroup Dynamic Group overlay no|yes|mod [no] --enable-dynlist Dynamic List overlay no|yes|mod [no] + --enable-memberof Reverse Group Membership overlay no|yes|mod [no] --enable-ppolicy Password Policy overlay no|yes|mod [no] --enable-proxycache Proxy Cache overlay no|yes|mod [no] --enable-refint Referential Integrity overlay no|yes|mod [no] @@ -1062,9 +1063,6 @@ SLAPD Overlay Options: --enable-unique Attribute Uniqueness overlay no|yes|mod [no] --enable-valsort Value Sorting overlay no|yes|mod [no] -SLURPD (Replication Daemon) Options: - --enable-slurpd enable building slurpd [auto] - Library Generation & Linking Options --enable-static[=PKGS] build static libraries [default=yes] @@ -1083,7 +1081,7 @@ Optional Packages: --with-cyrus-sasl with Cyrus SASL support [auto] --with-fetch with fetch(3) URL support [auto] --with-threads with threads [auto] - --with-tls with TLS/SSL support [auto] + --with-tls with TLS/SSL support auto|openssl|gnutls [auto] --with-yielding-select with implicitly yielding select [auto] --with-mp with multiple precision statistics auto|longlong|long|bignum|gmp [auto] --with-odbc with specific ODBC support iodbc|unixodbc|auto [auto] @@ -1595,8 +1593,11 @@ fi SHTOOL="$ac_cv_shtool" -TB="`$SHTOOL echo -e '%B' 2>/dev/null`" -TN="`$SHTOOL echo -e '%b' 2>/dev/null`" +TB="" TN="" +if test -t 1; then + TB="`$SHTOOL echo -e '%B' 2>/dev/null`" + TN="`$SHTOOL echo -e '%b' 2>/dev/null`" +fi OPENLDAP_CVS="" if test -d $ac_aux_dir/CVS; then @@ -2384,7 +2385,7 @@ if test "${with_tls+set}" = set; then withval="$with_tls" ol_arg=invalid - for ol_val in auto openssl yes no ; do + for ol_val in auto openssl gnutls yes no ; do if test "$withval" = "$ol_val" ; then ol_arg="$ol_val" fi @@ -3099,6 +3100,7 @@ Overlays="accesslog \ dds \ dyngroup \ dynlist \ + memberof \ ppolicy \ proxycache \ refint \ @@ -3281,6 +3283,30 @@ else fi; # end --enable-dynlist +# OpenLDAP --enable-memberof + + # Check whether --enable-memberof or --disable-memberof was given. +if test "${enable_memberof+set}" = set; then + enableval="$enable_memberof" + + ol_arg=invalid + for ol_val in no yes mod ; do + if test "$enableval" = "$ol_val" ; then + ol_arg="$ol_val" + fi + done + if test "$ol_arg" = "invalid" ; then + { { echo "$as_me:$LINENO: error: bad value $enableval for --enable-memberof" >&5 +echo "$as_me: error: bad value $enableval for --enable-memberof" >&2;} + { (exit 1); exit 1; }; } + fi + ol_enable_memberof="$ol_arg" + +else + ol_enable_memberof=${ol_enable_overlays:-no} +fi; +# end --enable-memberof + # OpenLDAP --enable-ppolicy # Check whether --enable-ppolicy or --disable-ppolicy was given. @@ -3522,35 +3548,6 @@ fi; # end --enable-valsort -# Check whether --enable-xxslurpdoptions or --disable-xxslurpdoptions was given. -if test "${enable_xxslurpdoptions+set}" = set; then - enableval="$enable_xxslurpdoptions" - -fi; -# OpenLDAP --enable-slurpd - - # Check whether --enable-slurpd or --disable-slurpd was given. -if test "${enable_slurpd+set}" = set; then - enableval="$enable_slurpd" - - ol_arg=invalid - for ol_val in auto yes no ; do - if test "$enableval" = "$ol_val" ; then - ol_arg="$ol_val" - fi - done - if test "$ol_arg" = "invalid" ; then - { { echo "$as_me:$LINENO: error: bad value $enableval for --enable-slurpd" >&5 -echo "$as_me: error: bad value $enableval for --enable-slurpd" >&2;} - { (exit 1); exit 1; }; } - fi - ol_enable_slurpd="$ol_arg" - -else - ol_enable_slurpd=auto -fi; -# end --enable-slurpd - # Check whether --enable-xxliboptions or --disable-xxliboptions was given. if test "${enable_xxliboptions+set}" = set; then enableval="$enable_xxliboptions" @@ -3643,11 +3640,6 @@ echo "$as_me: WARNING: slapd disabled, ignoring --enable-dynacl argument" >&2;} if test $ol_enable_aci != no ; then { echo "$as_me:$LINENO: WARNING: slapd disabled, ignoring --enable-aci argument" >&5 echo "$as_me: WARNING: slapd disabled, ignoring --enable-aci argument" >&2;} - fi - if test $ol_enable_slurpd = yes ; then - { { echo "$as_me:$LINENO: error: slurpd requires slapd" >&5 -echo "$as_me: error: slurpd requires slapd" >&2;} - { (exit 1); exit 1; }; } fi if test $ol_enable_rewrite = yes ; then { echo "$as_me:$LINENO: WARNING: slapd disabled, ignoring --enable-rewrite argument" >&5 @@ -3677,8 +3669,6 @@ echo "$as_me: WARNING: slapd disabled, ignoring --enable-$i argument" >&2;} ol_enable_aci=no ol_enable_wrappers=no - ol_enable_slurpd=no - ol_enable_rewrite=no elif test $ol_enable_modules != yes && @@ -3712,14 +3702,6 @@ echo "$as_me: error: --enable-meta requires --enable-ldap" >&2;} { (exit 1); exit 1; }; } fi -if test $ol_enable_slurpd = yes ; then - if test $ol_with_threads = no ; then - { { echo "$as_me:$LINENO: error: slurpd requires threads" >&5 -echo "$as_me: error: slurpd requires threads" >&2;} - { (exit 1); exit 1; }; } - fi -fi - if test $ol_enable_lmpasswd = yes ; then if test $ol_with_tls = no ; then { { echo "$as_me:$LINENO: error: LAN Manager passwords require OpenSSL" >&5 @@ -3746,10 +3728,8 @@ LTHREAD_LIBS= LUTIL_LIBS= SLAPD_LIBS= -SLURPD_LIBS= BUILD_SLAPD=no -BUILD_SLURPD=no BUILD_THREAD=no @@ -5613,7 +5593,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5616 "configure"' > conftest.$ac_ext + echo '#line 5596 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7593,11 +7573,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7596: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7576: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7600: \$? = $ac_status" >&5 + echo "$as_me:7580: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7855,11 +7835,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7858: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7838: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7862: \$? = $ac_status" >&5 + echo "$as_me:7842: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7917,11 +7897,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7920: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7900: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7924: \$? = $ac_status" >&5 + echo "$as_me:7904: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10165,7 +10145,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5 echo "${ECHO_T}$ol_cv_mkdep" >&6 + test "$ol_cv_mkdep" = no && OL_MKDEP=":" else cc_cv_mkdep=yes OL_MKDEP_FLAGS="${MKDEP_FLAGS}" @@ -13837,6 +13818,9 @@ fi + + + @@ -13871,9 +13855,11 @@ for ac_header in \ sysexits.h \ sys/file.h \ sys/filio.h \ + sys/fstyp.h \ sys/errno.h \ sys/ioctl.h \ sys/param.h \ + sys/privgrp.h \ sys/resource.h \ sys/select.h \ sys/socket.h \ @@ -13882,6 +13868,7 @@ for ac_header in \ sys/time.h \ sys/types.h \ sys/uio.h \ + sys/vmount.h \ syslog.h \ termios.h \ unistd.h \ @@ -17245,26 +17232,322 @@ _ACEOF fi if test $have_uuid = no ; then - echo "$as_me:$LINENO: checking to see if -lrpcrt4 is needed for win32 UUID support" >&5 -echo $ECHO_N "checking to see if -lrpcrt4 is needed for win32 UUID support... $ECHO_C" >&6 - save_LIBS="$LIBS" - LIBS="$LIBS -lrpcrt4" - cat >conftest.$ac_ext <<_ACEOF + +for ac_header in uuid/uuid.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 - int __stdcall UuidCreate(void *); - int __stdcall UuidToStringA(void *,void **); +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------------------------- ## +## Report this to ## +## --------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + if test $ac_cv_header_uuid_uuid_h = yes ; then + save_LIBS="$LIBS" + echo "$as_me:$LINENO: checking for library containing uuid_generate" >&5 +echo $ECHO_N "checking for library containing uuid_generate... $ECHO_C" >&6 +if test "${ac_cv_search_uuid_generate+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_uuid_generate=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char uuid_generate (); int main () { +uuid_generate (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_uuid_generate="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 - UuidCreate(0); - UuidToStringA(0,0); +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_uuid_generate" = no; then + for ac_lib in uuid; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char uuid_generate (); +int +main () +{ +uuid_generate (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_uuid_generate="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_uuid_generate" >&5 +echo "${ECHO_T}$ac_cv_search_uuid_generate" >&6 +if test "$ac_cv_search_uuid_generate" != no; then + test "$ac_cv_search_uuid_generate" = "none required" || LIBS="$ac_cv_search_uuid_generate $LIBS" + have_uuid=yes +else + : +fi + + LIBS="$save_LIBS" + + if test have_uuid = yes ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_UUID_GENERATE 1 +_ACEOF + + + test "$ac_cv_search_uuid_generate" = "none required" || \ + SLAPD_LIBS="$SLAPD_LIBS $ac_cv_search_uuid_generate" + fi + fi +fi + +if test $have_uuid = no ; then + echo "$as_me:$LINENO: checking to see if -lrpcrt4 is needed for win32 UUID support" >&5 +echo $ECHO_N "checking to see if -lrpcrt4 is needed for win32 UUID support... $ECHO_C" >&6 + save_LIBS="$LIBS" + LIBS="$LIBS -lrpcrt4" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + int __stdcall UuidCreate(void *); + int __stdcall UuidToStringA(void *,void **); + +int +main () +{ + + UuidCreate(0); + UuidToStringA(0,0); ; return 0; @@ -18525,6 +18808,247 @@ _ACEOF fi fi +if test $ol_link_tls = no ; then + if test $ol_with_tls = gnutls || test $ol_with_tls = auto ; then + +for ac_header in gnutls/gnutls.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------------------------- ## +## Report this to ## +## --------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + if test $ac_cv_header_gnutls_gnutls_h = yes ; then + echo "$as_me:$LINENO: checking for gnutls_init in -lgnutls" >&5 +echo $ECHO_N "checking for gnutls_init in -lgnutls... $ECHO_C" >&6 +if test "${ac_cv_lib_gnutls_gnutls_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gnutls_init (); +int +main () +{ +gnutls_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_gnutls_gnutls_init=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_gnutls_gnutls_init=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_gnutls_gnutls_init" >&5 +echo "${ECHO_T}$ac_cv_lib_gnutls_gnutls_init" >&6 +if test $ac_cv_lib_gnutls_gnutls_init = yes; then + have_gnutls=yes +else + have_gnutls=no +fi + + + if test $have_gnutls = yes ; then + ol_with_tls=gnutls + ol_link_tls=yes + + TLS_LIBS="-lgnutls" + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GNUTLS 1 +_ACEOF + + fi + fi + fi +fi + WITH_TLS=no if test $ol_link_tls = yes ; then @@ -23879,7 +24403,7 @@ int main(argc, argv) #endif /* make sure task runs first */ -#if HAVE_THR_YIELD +#ifdef HAVE_THR_YIELD thr_yield(); #elif defined( HAVE_SCHED_YIELD ) sched_yield(); @@ -30649,9 +31173,9 @@ main() } #if (DB_VERSION_MAJOR > 3) || (DB_VERSION_MINOR >= 1) - rc = env->open( env, NULL, flags, 0 ); + rc = (env->open)( env, NULL, flags, 0 ); #else - rc = env->open( env, NULL, NULL, flags, 0 ); + rc = (env->open)( env, NULL, NULL, flags, 0 ); #endif if ( rc == 0 ) { @@ -33518,6 +34042,7 @@ _ACEOF fi + echo "$as_me:$LINENO: checking for socklen_t" >&5 echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6 if test "${ac_cv_type_socklen_t+set}" = set; then @@ -33534,7 +34059,6 @@ $ac_includes_default #include #endif - int main () { @@ -33579,12 +34103,84 @@ rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5 echo "${ECHO_T}$ac_cv_type_socklen_t" >&6 -if test $ac_cv_type_socklen_t = yes; then - : + + +echo "$as_me:$LINENO: checking the type of arg 3 to accept()" >&5 +echo $ECHO_N "checking the type of arg 3 to accept()... $ECHO_C" >&6 +if test "${ol_cv_type_ber_socklen_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + set socklen_t int unsigned "unsigned long" long size_t + test "$ac_cv_type_socklen_t" = yes || shift + ol_cv_type_ber_socklen_t=$1 guessing="guessing " + for lentype in "$@" ; do for addrtype in "struct sockaddr" void ; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +extern int accept(int s, $addrtype *ap, $lentype *lp); + +int +main () +{ + +accept(0, (struct sockaddr *) 0, ($lentype *) 0); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ol_cv_type_ber_socklen_t=$lentype guessing= ; break 2 else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done ; done +fi + +echo "$as_me:$LINENO: result: $guessing$ol_cv_type_ber_socklen_t *" >&5 +echo "${ECHO_T}$guessing$ol_cv_type_ber_socklen_t *" >&6 cat >>confdefs.h <<_ACEOF -#define socklen_t int +#define ber_socklen_t $ol_cv_type_ber_socklen_t +_ACEOF + + +if test "$ac_cv_type_socklen_t" != yes; then + +cat >>confdefs.h <<_ACEOF +#define socklen_t $ol_cv_type_ber_socklen_t _ACEOF fi @@ -38855,7 +39451,126 @@ int main () { static struct msghdr ac_aggr; -if (sizeof ac_aggr.msg_accrightslen) +if (sizeof ac_aggr.msg_accrightslen) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_msghdr_msg_accrightslen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_msghdr_msg_accrightslen=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_accrightslen" >&5 +echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_accrightslen" >&6 +if test $ac_cv_member_struct_msghdr_msg_accrightslen = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN 1 +_ACEOF + + +fi + + if test "$ac_cv_member_struct_msghdr_msg_accrightslen" != yes; then + echo "$as_me:$LINENO: checking for struct msghdr.msg_control" >&5 +echo $ECHO_N "checking for struct msghdr.msg_control... $ECHO_C" >&6 +if test "${ac_cv_member_struct_msghdr_msg_control+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +int +main () +{ +static struct msghdr ac_aggr; +if (ac_aggr.msg_control) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_msghdr_msg_control=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +int +main () +{ +static struct msghdr ac_aggr; +if (sizeof ac_aggr.msg_control) return 0; ; return 0; @@ -38883,32 +39598,32 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_member_struct_msghdr_msg_accrightslen=yes + ac_cv_member_struct_msghdr_msg_control=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_member_struct_msghdr_msg_accrightslen=no +ac_cv_member_struct_msghdr_msg_control=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_accrightslen" >&5 -echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_accrightslen" >&6 -if test $ac_cv_member_struct_msghdr_msg_accrightslen = yes; then +echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_control" >&5 +echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_control" >&6 +if test $ac_cv_member_struct_msghdr_msg_control = yes; then cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN 1 +#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 _ACEOF fi - if test "$ac_cv_member_struct_msghdr_msg_accrightslen" != yes; then - echo "$as_me:$LINENO: checking for struct msghdr.msg_control" >&5 -echo $ECHO_N "checking for struct msghdr.msg_control... $ECHO_C" >&6 -if test "${ac_cv_member_struct_msghdr_msg_control+set}" = set; then + fi + echo "$as_me:$LINENO: checking for struct stat.st_fstype" >&5 +echo $ECHO_N "checking for struct stat.st_fstype... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_fstype+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -38918,15 +39633,11 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - int main () { -static struct msghdr ac_aggr; -if (ac_aggr.msg_control) +static struct stat ac_aggr; +if (ac_aggr.st_fstype) return 0; ; return 0; @@ -38954,7 +39665,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_member_struct_msghdr_msg_control=yes + ac_cv_member_struct_stat_st_fstype=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 @@ -38966,15 +39677,76 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default -#ifdef HAVE_SYS_SOCKET_H -#include -#endif +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_fstype) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_fstype=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 +ac_cv_member_struct_stat_st_fstype=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_fstype" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_fstype" >&6 +if test $ac_cv_member_struct_stat_st_fstype = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_FSTYPE 1 +_ACEOF + + +fi +echo "$as_me:$LINENO: checking for struct stat.st_vfstype" >&5 +echo $ECHO_N "checking for struct stat.st_vfstype... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_vfstype+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default int main () { -static struct msghdr ac_aggr; -if (sizeof ac_aggr.msg_control) +static struct stat ac_aggr; +if (ac_aggr.st_vfstype) return 0; ; return 0; @@ -39002,28 +39774,114 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_member_struct_msghdr_msg_control=yes + ac_cv_member_struct_stat_st_vfstype=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_member_struct_msghdr_msg_control=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_vfstype) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_vfstype=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_stat_st_vfstype=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_control" >&5 -echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_control" >&6 -if test $ac_cv_member_struct_msghdr_msg_control = yes; then +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_vfstype" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_vfstype" >&6 +if test $ac_cv_member_struct_stat_st_vfstype = yes; then cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 +#define HAVE_STRUCT_STAT_ST_VFSTYPE 1 _ACEOF fi + if test "$ac_cv_member_struct_stat_st_fstype" = yes; then + cat >conftest.$ac_ext <<_ACEOF +struct stat st; char *ptr=st.st_fstype; +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STRUCT_STAT_ST_FSTYPE_CHAR 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STRUCT_STAT_ST_FSTYPE_INT 1 +_ACEOF + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi fi LIBSRCS="$LIBSRCS getpeereid.c" @@ -39728,6 +40586,22 @@ _ACEOF fi +if test "$ol_enable_memberof" != no ; then + BUILD_MEMBEROF=$ol_enable_memberof + if test "$ol_enable_memberof" = mod ; then + MFLAG=SLAPD_MOD_DYNAMIC + SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS memberof.la" + else + MFLAG=SLAPD_MOD_STATIC + SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS memberof.o" + fi + +cat >>confdefs.h <<_ACEOF +#define SLAPD_OVER_MEMBEROF $MFLAG +_ACEOF + +fi + if test "$ol_enable_ppolicy" != no ; then BUILD_PPOLICY=$ol_enable_ppolicy if test "$ol_enable_ppolicy" = mod ; then @@ -39889,12 +40763,6 @@ _ACEOF fi -if test "$ol_enable_slurpd" != no && - test "$ol_link_threads" != no && - test $BUILD_SLAPD = yes ; then - BUILD_SLURPD=yes -fi - if test "$ol_enable_rewrite" != no ; then cat >>confdefs.h <<\_ACEOF @@ -40002,8 +40870,6 @@ fi - - @@ -40014,7 +40880,7 @@ if test "${with_xxinstall+set}" = set; then fi; - ac_config_files="$ac_config_files Makefile:build/top.mk:Makefile.in:build/dir.mk doc/Makefile:build/top.mk:doc/Makefile.in:build/dir.mk doc/man/Makefile:build/top.mk:doc/man/Makefile.in:build/dir.mk doc/man/man1/Makefile:build/top.mk:doc/man/man1/Makefile.in:build/man.mk doc/man/man3/Makefile:build/top.mk:doc/man/man3/Makefile.in:build/man.mk doc/man/man5/Makefile:build/top.mk:doc/man/man5/Makefile.in:build/man.mk doc/man/man8/Makefile:build/top.mk:doc/man/man8/Makefile.in:build/man.mk clients/Makefile:build/top.mk:clients/Makefile.in:build/dir.mk clients/tools/Makefile:build/top.mk:clients/tools/Makefile.in:build/rules.mk include/Makefile:build/top.mk:include/Makefile.in libraries/Makefile:build/top.mk:libraries/Makefile.in:build/dir.mk libraries/liblber/Makefile:build/top.mk:libraries/liblber/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/libldap/Makefile:build/top.mk:libraries/libldap/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/libldap_r/Makefile:build/top.mk:libraries/libldap_r/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/liblunicode/Makefile:build/top.mk:libraries/liblunicode/Makefile.in:build/lib.mk:build/lib-static.mk libraries/liblutil/Makefile:build/top.mk:libraries/liblutil/Makefile.in:build/lib.mk:build/lib-static.mk libraries/librewrite/Makefile:build/top.mk:libraries/librewrite/Makefile.in:build/lib.mk:build/lib-static.mk servers/Makefile:build/top.mk:servers/Makefile.in:build/dir.mk servers/slapd/Makefile:build/top.mk:servers/slapd/Makefile.in:build/srv.mk servers/slapd/back-bdb/Makefile:build/top.mk:servers/slapd/back-bdb/Makefile.in:build/mod.mk servers/slapd/back-dnssrv/Makefile:build/top.mk:servers/slapd/back-dnssrv/Makefile.in:build/mod.mk servers/slapd/back-hdb/Makefile:build/top.mk:servers/slapd/back-hdb/Makefile.in:build/mod.mk servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.in:build/mod.mk servers/slapd/back-ldif/Makefile:build/top.mk:servers/slapd/back-ldif/Makefile.in:build/mod.mk servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk servers/slapd/back-relay/Makefile:build/top.mk:servers/slapd/back-relay/Makefile.in:build/mod.mk servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk servers/slapd/back-sql/Makefile:build/top.mk:servers/slapd/back-sql/Makefile.in:build/mod.mk servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk servers/slurpd/Makefile:build/top.mk:servers/slurpd/Makefile.in:build/srv.mk tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk tests/run tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk" + ac_config_files="$ac_config_files Makefile:build/top.mk:Makefile.in:build/dir.mk doc/Makefile:build/top.mk:doc/Makefile.in:build/dir.mk doc/man/Makefile:build/top.mk:doc/man/Makefile.in:build/dir.mk doc/man/man1/Makefile:build/top.mk:doc/man/man1/Makefile.in:build/man.mk doc/man/man3/Makefile:build/top.mk:doc/man/man3/Makefile.in:build/man.mk doc/man/man5/Makefile:build/top.mk:doc/man/man5/Makefile.in:build/man.mk doc/man/man8/Makefile:build/top.mk:doc/man/man8/Makefile.in:build/man.mk clients/Makefile:build/top.mk:clients/Makefile.in:build/dir.mk clients/tools/Makefile:build/top.mk:clients/tools/Makefile.in:build/rules.mk include/Makefile:build/top.mk:include/Makefile.in libraries/Makefile:build/top.mk:libraries/Makefile.in:build/dir.mk libraries/liblber/Makefile:build/top.mk:libraries/liblber/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/libldap/Makefile:build/top.mk:libraries/libldap/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/libldap_r/Makefile:build/top.mk:libraries/libldap_r/Makefile.in:build/lib.mk:build/lib-shared.mk libraries/liblunicode/Makefile:build/top.mk:libraries/liblunicode/Makefile.in:build/lib.mk:build/lib-static.mk libraries/liblutil/Makefile:build/top.mk:libraries/liblutil/Makefile.in:build/lib.mk:build/lib-static.mk libraries/librewrite/Makefile:build/top.mk:libraries/librewrite/Makefile.in:build/lib.mk:build/lib-static.mk servers/Makefile:build/top.mk:servers/Makefile.in:build/dir.mk servers/slapd/Makefile:build/top.mk:servers/slapd/Makefile.in:build/srv.mk servers/slapd/back-bdb/Makefile:build/top.mk:servers/slapd/back-bdb/Makefile.in:build/mod.mk servers/slapd/back-dnssrv/Makefile:build/top.mk:servers/slapd/back-dnssrv/Makefile.in:build/mod.mk servers/slapd/back-hdb/Makefile:build/top.mk:servers/slapd/back-hdb/Makefile.in:build/mod.mk servers/slapd/back-ldap/Makefile:build/top.mk:servers/slapd/back-ldap/Makefile.in:build/mod.mk servers/slapd/back-ldif/Makefile:build/top.mk:servers/slapd/back-ldif/Makefile.in:build/mod.mk servers/slapd/back-meta/Makefile:build/top.mk:servers/slapd/back-meta/Makefile.in:build/mod.mk servers/slapd/back-monitor/Makefile:build/top.mk:servers/slapd/back-monitor/Makefile.in:build/mod.mk servers/slapd/back-null/Makefile:build/top.mk:servers/slapd/back-null/Makefile.in:build/mod.mk servers/slapd/back-passwd/Makefile:build/top.mk:servers/slapd/back-passwd/Makefile.in:build/mod.mk servers/slapd/back-perl/Makefile:build/top.mk:servers/slapd/back-perl/Makefile.in:build/mod.mk servers/slapd/back-relay/Makefile:build/top.mk:servers/slapd/back-relay/Makefile.in:build/mod.mk servers/slapd/back-shell/Makefile:build/top.mk:servers/slapd/back-shell/Makefile.in:build/mod.mk servers/slapd/back-sql/Makefile:build/top.mk:servers/slapd/back-sql/Makefile.in:build/mod.mk servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk tests/run tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk" ac_config_commands="$ac_config_commands default" @@ -40561,7 +41427,6 @@ do "servers/slapd/shell-backends/Makefile" ) CONFIG_FILES="$CONFIG_FILES servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk" ;; "servers/slapd/slapi/Makefile" ) CONFIG_FILES="$CONFIG_FILES servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk" ;; "servers/slapd/overlays/Makefile" ) CONFIG_FILES="$CONFIG_FILES servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk" ;; - "servers/slurpd/Makefile" ) CONFIG_FILES="$CONFIG_FILES servers/slurpd/Makefile:build/top.mk:servers/slurpd/Makefile.in:build/srv.mk" ;; "tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk" ;; "tests/run" ) CONFIG_FILES="$CONFIG_FILES tests/run" ;; "tests/progs/Makefile" ) CONFIG_FILES="$CONFIG_FILES tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk" ;; @@ -40771,10 +41636,8 @@ s,@BUILD_SYNCPROV@,$BUILD_SYNCPROV,;t t s,@BUILD_TRANSLUCENT@,$BUILD_TRANSLUCENT,;t t s,@BUILD_UNIQUE@,$BUILD_UNIQUE,;t t s,@BUILD_VALSORT@,$BUILD_VALSORT,;t t -s,@BUILD_SLURPD@,$BUILD_SLURPD,;t t s,@LDAP_LIBS@,$LDAP_LIBS,;t t s,@SLAPD_LIBS@,$SLAPD_LIBS,;t t -s,@SLURPD_LIBS@,$SLURPD_LIBS,;t t s,@BDB_LIBS@,$BDB_LIBS,;t t s,@LTHREAD_LIBS@,$LTHREAD_LIBS,;t t s,@LUTIL_LIBS@,$LUTIL_LIBS,;t t @@ -41595,7 +42458,11 @@ fi /* end of generated file */ ENDX -echo Please run \"make depend\" to build dependencies +if test "${ol_cv_mkdep}" = no; then + echo '(Do not "make depend"; we do not know how to build dependencies)' +else + echo 'Please run "make depend" to build dependencies' +fi ;; esac done diff --git a/configure.in b/configure.in index b013b04f73..cad9a70bbb 100644 --- a/configure.in +++ b/configure.in @@ -50,8 +50,11 @@ fi SHTOOL="$ac_cv_shtool" dnl AC_SUBST(SHTOOL)dnl -TB="`$SHTOOL echo -e '%B' 2>/dev/null`" -TN="`$SHTOOL echo -e '%b' 2>/dev/null`" +TB="" TN="" +if test -t 1; then + TB="`$SHTOOL echo -e '%B' 2>/dev/null`" + TN="`$SHTOOL echo -e '%b' 2>/dev/null`" +fi OPENLDAP_CVS="" if test -d $ac_aux_dir/CVS; then @@ -241,8 +244,8 @@ OL_ARG_WITH(fetch,[ --with-fetch with fetch(3) URL support], auto, [auto yes no] ) OL_ARG_WITH(threads,[ --with-threads with threads], auto, [auto nt posix mach pth lwp yes no manual] ) -OL_ARG_WITH(tls,[ --with-tls with TLS/SSL support], - auto, [auto openssl yes no] ) +OL_ARG_WITH(tls,[ --with-tls with TLS/SSL support auto|openssl|gnutls], + auto, [auto openssl gnutls yes no] ) OL_ARG_WITH(yielding_select, [ --with-yielding-select with implicitly yielding select], auto, [auto yes no manual] ) @@ -328,6 +331,7 @@ Overlays="accesslog \ dds \ dyngroup \ dynlist \ + memberof \ ppolicy \ proxycache \ refint \ @@ -356,6 +360,8 @@ OL_ARG_ENABLE(dyngroup,[ --enable-dyngroup Dynamic Group overlay], no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(dynlist,[ --enable-dynlist Dynamic List overlay], no, [no yes mod], ol_enable_overlays) +OL_ARG_ENABLE(memberof,[ --enable-memberof Reverse Group Membership overlay], + no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(ppolicy,[ --enable-ppolicy Password Policy overlay], no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(proxycache,[ --enable-proxycache Proxy Cache overlay], @@ -377,12 +383,6 @@ OL_ARG_ENABLE(unique,[ --enable-unique Attribute Uniqueness overlay], OL_ARG_ENABLE(valsort,[ --enable-valsort Value Sorting overlay], no, [no yes mod], ol_enable_overlays) -dnl ---------------------------------------------------------------- -dnl SLURPD OPTIONS -AC_ARG_ENABLE(xxslurpdoptions,[ -SLURPD (Replication Daemon) Options:]) -OL_ARG_ENABLE(slurpd,[ --enable-slurpd enable building slurpd], auto)dnl - dnl ---------------------------------------------------------------- AC_ARG_ENABLE(xxliboptions,[ Library Generation & Linking Options]) @@ -422,9 +422,6 @@ if test $ol_enable_slapd = no ; then if test $ol_enable_aci != no ; then AC_MSG_WARN([slapd disabled, ignoring --enable-aci argument]) fi - if test $ol_enable_slurpd = yes ; then - AC_MSG_ERROR([slurpd requires slapd]) - fi if test $ol_enable_rewrite = yes ; then AC_MSG_WARN([slapd disabled, ignoring --enable-rewrite argument]) fi @@ -451,8 +448,6 @@ if test $ol_enable_slapd = no ; then ol_enable_aci=no ol_enable_wrappers=no - ol_enable_slurpd=no - ol_enable_rewrite=no elif test $ol_enable_modules != yes && @@ -482,13 +477,6 @@ if test $ol_enable_meta/$ol_enable_ldap = yes/no ; then AC_MSG_ERROR([--enable-meta requires --enable-ldap]) fi -if test $ol_enable_slurpd = yes ; then - dnl SLURPD was specifically enabled - if test $ol_with_threads = no ; then - AC_MSG_ERROR([slurpd requires threads]) - fi -fi - if test $ol_enable_lmpasswd = yes ; then if test $ol_with_tls = no ; then AC_MSG_ERROR([LAN Manager passwords require OpenSSL]) @@ -512,10 +500,8 @@ LTHREAD_LIBS= LUTIL_LIBS= SLAPD_LIBS= -SLURPD_LIBS= BUILD_SLAPD=no -BUILD_SLURPD=no BUILD_THREAD=no @@ -813,9 +799,11 @@ AC_CHECK_HEADERS( \ sysexits.h \ sys/file.h \ sys/filio.h \ + sys/fstyp.h \ sys/errno.h \ sys/ioctl.h \ sys/param.h \ + sys/privgrp.h \ sys/resource.h \ sys/select.h \ sys/socket.h \ @@ -824,6 +812,7 @@ AC_CHECK_HEADERS( \ sys/time.h \ sys/types.h \ sys/uio.h \ + sys/vmount.h \ syslog.h \ termios.h \ unistd.h \ @@ -988,7 +977,7 @@ have_uuid=no AC_CHECK_HEADERS(sys/uuid.h) if test $ac_cv_header_sys_uuid_h = yes ; then save_LIBS="$LIBS" - AC_SEARCH_LIBS(uuid_to_str, uuid, [have_uuid=yes], :) + AC_SEARCH_LIBS([uuid_to_str], [uuid], [have_uuid=yes], :) LIBS="$save_LIBS" if test have_uuid = yes ; then @@ -1000,6 +989,24 @@ if test $ac_cv_header_sys_uuid_h = yes ; then fi fi +dnl Look for uuid_generate +if test $have_uuid = no ; then + AC_CHECK_HEADERS(uuid/uuid.h) + if test $ac_cv_header_uuid_uuid_h = yes ; then + save_LIBS="$LIBS" + AC_SEARCH_LIBS([uuid_generate], [uuid], [have_uuid=yes], :) + LIBS="$save_LIBS" + + if test have_uuid = yes ; then + AC_DEFINE(HAVE_UUID_GENERATE,1, + [define if you have uuid_generate()]) + + test "$ac_cv_search_uuid_generate" = "none required" || \ + SLAPD_LIBS="$SLAPD_LIBS $ac_cv_search_uuid_generate" + fi + fi +fi + dnl For windows, check for the need of RPCRT for UUID function support if test $have_uuid = no ; then AC_MSG_CHECKING(to see if -lrpcrt4 is needed for win32 UUID support) @@ -1146,6 +1153,27 @@ if test $ol_with_tls = openssl || test $ol_with_tls = auto ; then fi fi +if test $ol_link_tls = no ; then + if test $ol_with_tls = gnutls || test $ol_with_tls = auto ; then + AC_CHECK_HEADERS(gnutls/gnutls.h) + + if test $ac_cv_header_gnutls_gnutls_h = yes ; then + AC_CHECK_LIB(gnutls, gnutls_init, + [have_gnutls=yes], [have_gnutls=no]) + + if test $have_gnutls = yes ; then + ol_with_tls=gnutls + ol_link_tls=yes + + TLS_LIBS="-lgnutls" + + AC_DEFINE(HAVE_GNUTLS, 1, + [define if you have GNUtls]) + fi + fi + fi +fi + WITH_TLS=no if test $ol_link_tls = yes ; then AC_DEFINE(HAVE_TLS, 1, [define if you have TLS]) @@ -1471,7 +1499,7 @@ int main(argc, argv) #endif /* make sure task runs first */ -#if HAVE_THR_YIELD +#ifdef HAVE_THR_YIELD thr_yield(); #elif defined( HAVE_SCHED_YIELD ) sched_yield(); @@ -2108,14 +2136,43 @@ AC_CHECK_TYPE(size_t, unsigned) AC_CHECK_TYPES([long long]) AC_CHECK_TYPES([ptrdiff_t]) -AC_CHECK_TYPE([socklen_t],, - [AC_DEFINE_UNQUOTED([socklen_t], [int], - [Define to `int' if does not define.])], - [$ac_includes_default + +AC_CHECK_TYPE([socklen_t],,, [$ac_includes_default +#ifdef HAVE_SYS_SOCKET_H +#include +#endif]) + +dnl socklen_t-like type in accept(), default socklen_t or int: +dnl - The OS might define socklen_t without using it. POSIX moved from +dnl int to size_t to socklen_t, hoping to stay at a 32-bit type, and +dnl HP-UX now has selectors for what to use. +dnl - On Solaris 2.8 the prototype has void *len, but the default is OK. +AC_MSG_CHECKING([the type of arg 3 to accept()]) +AC_CACHE_VAL(ol_cv_type_ber_socklen_t, [ + set socklen_t int unsigned "unsigned long" long size_t + test "$ac_cv_type_socklen_t" = yes || shift + ol_cv_type_ber_socklen_t=$1 guessing="guessing " + for lentype in "$@" ; do for addrtype in "struct sockaddr" void ; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_includes_default #ifdef HAVE_SYS_SOCKET_H #include #endif - ]) +extern int accept(int s, $addrtype *ap, $lentype *lp); +], [ +accept(0, (struct sockaddr *) 0, ($lentype *) 0); +])], [ol_cv_type_ber_socklen_t=$lentype guessing= ; break 2]) + done ; done]) +AC_MSG_RESULT([$guessing$ol_cv_type_ber_socklen_t *]) +AC_DEFINE_UNQUOTED(ber_socklen_t, $ol_cv_type_ber_socklen_t, + [Define to the type of arg 3 for `accept'.]) + +dnl Modules should use ber_socklen_t, not socklen_t. Define socklen_t +dnl for the time being anyway, for backwards compatibility. +if test "$ac_cv_type_socklen_t" != yes; then + AC_DEFINE_UNQUOTED([socklen_t], [$ol_cv_type_ber_socklen_t], + [Define like ber_socklen_t if does not define.]) +fi + AC_TYPE_SIGNAL @@ -2320,6 +2377,12 @@ if test "$ac_cv_func_getpeereid" != yes; then #include #endif]) fi + AC_CHECK_MEMBERS([struct stat.st_fstype, struct stat.st_vfstype]) + if test "$ac_cv_member_struct_stat_st_fstype" = yes; then + AC_COMPILE_IFELSE([struct stat st; char *ptr=st.st_fstype;], + AC_DEFINE([HAVE_STRUCT_STAT_ST_FSTYPE_CHAR],1,[define to 1 if st_fstype is char *]), + AC_DEFINE([HAVE_STRUCT_STAT_ST_FSTYPE_INT],1,[define to 1 if st_fstype is int])) + fi fi LIBSRCS="$LIBSRCS getpeereid.c" fi @@ -2656,6 +2719,18 @@ if test "$ol_enable_dynlist" != no ; then AC_DEFINE_UNQUOTED(SLAPD_OVER_DYNLIST,$MFLAG,[define for Dynamic List overlay]) fi +if test "$ol_enable_memberof" != no ; then + BUILD_MEMBEROF=$ol_enable_memberof + if test "$ol_enable_memberof" = mod ; then + MFLAG=SLAPD_MOD_DYNAMIC + SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS memberof.la" + else + MFLAG=SLAPD_MOD_STATIC + SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS memberof.o" + fi + AC_DEFINE_UNQUOTED(SLAPD_OVER_MEMBEROF,$MFLAG,[define for Reverse Group Membership overlay]) +fi + if test "$ol_enable_ppolicy" != no ; then BUILD_PPOLICY=$ol_enable_ppolicy if test "$ol_enable_ppolicy" = mod ; then @@ -2777,12 +2852,6 @@ if test "$ol_enable_valsort" != no ; then AC_DEFINE_UNQUOTED(SLAPD_OVER_VALSORT,$MFLAG,[define for Value Sorting overlay]) fi -if test "$ol_enable_slurpd" != no && - test "$ol_link_threads" != no && - test $BUILD_SLAPD = yes ; then - BUILD_SLURPD=yes -fi - if test "$ol_enable_rewrite" != no ; then AC_DEFINE(ENABLE_REWRITE,1,[define to enable rewriting in back-ldap and back-meta]) BUILD_REWRITE=yes @@ -2853,11 +2922,9 @@ dnl overlays AC_SUBST(BUILD_TRANSLUCENT) AC_SUBST(BUILD_UNIQUE) AC_SUBST(BUILD_VALSORT) -AC_SUBST(BUILD_SLURPD) AC_SUBST(LDAP_LIBS) AC_SUBST(SLAPD_LIBS) -AC_SUBST(SLURPD_LIBS) AC_SUBST(BDB_LIBS) AC_SUBST(LTHREAD_LIBS) AC_SUBST(LUTIL_LIBS) @@ -2938,7 +3005,6 @@ AC_CONFIG_FILES([Makefile:build/top.mk:Makefile.in:build/dir.mk] [servers/slapd/shell-backends/Makefile:build/top.mk:servers/slapd/shell-backends/Makefile.in:build/srv.mk] [servers/slapd/slapi/Makefile:build/top.mk:servers/slapd/slapi/Makefile.in:build/lib.mk:build/lib-shared.mk] [servers/slapd/overlays/Makefile:build/top.mk:servers/slapd/overlays/Makefile.in:build/lib.mk] -[servers/slurpd/Makefile:build/top.mk:servers/slurpd/Makefile.in:build/srv.mk] [tests/Makefile:build/top.mk:tests/Makefile.in:build/dir.mk] [tests/run] [tests/progs/Makefile:build/top.mk:tests/progs/Makefile.in:build/rules.mk]) @@ -3051,7 +3117,11 @@ fi /* end of generated file */ ENDX -echo Please run \"make depend\" to build dependencies +if test "${ol_cv_mkdep}" = no; then + echo '(Do not "make depend"; we do not know how to build dependencies)' +else + echo 'Please run "make depend" to build dependencies' +fi ]],[[ STATIC_BACKENDS="$SLAPD_STATIC_BACKENDS" STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS" diff --git a/contrib/ldapc++/src/ac/time.h b/contrib/ldapc++/src/ac/time.h index 332d96d053..94db3bb1b2 100644 --- a/contrib/ldapc++/src/ac/time.h +++ b/contrib/ldapc++/src/ac/time.h @@ -13,10 +13,10 @@ #ifndef _AC_TIME_H #define _AC_TIME_H -#if TIME_WITH_SYS_TIME +#ifdef TIME_WITH_SYS_TIME # include # include -#elif HAVE_SYS_TIME_H +#elif defined HAVE_SYS_TIME_H # include # ifdef HAVE_SYS_TIMEB_H # include diff --git a/contrib/ldaptcl/configure b/contrib/ldaptcl/configure index 2137d294fb..731d3aba12 100755 --- a/contrib/ldaptcl/configure +++ b/contrib/ldaptcl/configure @@ -931,7 +931,8 @@ fi case "$with_tk" in yes) - if test -f $exec_prefix/lib/tkConfig.sh -a $exec_prefix/lib/tkxConfig.sh + if test -f $exec_prefix/lib/tkConfig.sh && + test -f $exec_prefix/lib/tkxConfig.sh then : else diff --git a/contrib/ldaptcl/configure.in b/contrib/ldaptcl/configure.in index 71ac2a67b1..9a0364c3a7 100644 --- a/contrib/ldaptcl/configure.in +++ b/contrib/ldaptcl/configure.in @@ -52,7 +52,8 @@ AC_ARG_WITH(tk, [ --with-tk=DIR use Tk 8.0 binaries from DIR], case "$with_tk" in yes) - if test -f $exec_prefix/lib/tkConfig.sh -a $exec_prefix/lib/tkxConfig.sh + if test -f $exec_prefix/lib/tkConfig.sh && + test -f $exec_prefix/lib/tkxConfig.sh then : else diff --git a/contrib/ldaptcl/neoXldap.c b/contrib/ldaptcl/neoXldap.c index a9f1a8f2b9..b1ce03e705 100644 --- a/contrib/ldaptcl/neoXldap.c +++ b/contrib/ldaptcl/neoXldap.c @@ -1408,7 +1408,7 @@ NeoX_LdapObjCmd (clientData, interp, objc, objv) } ldap = ldap_init (ldapHost, ldapPort); -#if LDAP_OPT_PROTOCOL_VERSION +#ifdef LDAP_OPT_PROTOCOL_VERSION if (version != -1) ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version); #endif @@ -1426,7 +1426,7 @@ NeoX_LdapObjCmd (clientData, interp, objc, objv) return TCL_ERROR; } -#if UMICH_LDAP +#ifdef UMICH_LDAP ldap->ld_deref = LDAP_DEREF_NEVER; /* Turn off alias dereferencing */ #endif diff --git a/contrib/slapd-modules/addpartial/COPYRIGHT b/contrib/slapd-modules/addpartial/COPYRIGHT new file mode 100644 index 0000000000..fda001e3c7 --- /dev/null +++ b/contrib/slapd-modules/addpartial/COPYRIGHT @@ -0,0 +1,10 @@ +Copyright (C) Virginia Tech, David Hawes. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in file LICENSE in the +top-level directory of the distribution or, alternatively, at +http://www.OpenLDAP.org/license.html. diff --git a/contrib/slapd-modules/addpartial/LICENSE b/contrib/slapd-modules/addpartial/LICENSE new file mode 100644 index 0000000000..83a87efa84 --- /dev/null +++ b/contrib/slapd-modules/addpartial/LICENSE @@ -0,0 +1,47 @@ +The OpenLDAP Public License + Version 2.8, 17 August 2003 + + Redistribution and use of this software and associated documentation + ("Software"), with or without modification, are permitted provided + that the following conditions are met: + + 1. Redistributions in source form must retain copyright statements + and notices, + + 2. Redistributions in binary form must reproduce applicable copyright + statements and notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution, and + + 3. Redistributions must contain a verbatim copy of this document. + +The OpenLDAP Foundation may revise this license from time to time. +Each revision is distinguished by a version number. You may use +this Software under terms of this license revision or under the +terms of any subsequent revision of the license. + +THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS +CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S) +OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +The names of the authors and copyright holders must not be used in +advertising or otherwise to promote the sale, use or other dealing +in this Software without specific, written prior permission. Title +to copyright in this Software shall at all times remain with copyright +holders. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. + +Copyright 1999-2003 The OpenLDAP Foundation, Redwood City, +California, USA. All Rights Reserved. Permission to copy and +distribute verbatim copies of this document is granted. diff --git a/contrib/slapd-modules/addpartial/Makefile b/contrib/slapd-modules/addpartial/Makefile new file mode 100644 index 0000000000..60a1b592ca --- /dev/null +++ b/contrib/slapd-modules/addpartial/Makefile @@ -0,0 +1,12 @@ +OPENLDAP_SRC=/usr/local/src/openldap-2.3.32 +CPPFLAGS+=-I${OPENLDAP_SRC}/include -I${OPENLDAP_SRC}/servers/slapd +LDFLAGS+=-L/usr/local/openldap-2.3.32/lib +CC=gcc + +all: addpartial-overlay.so + +addpartial-overlay.so: addpartial-overlay.c + $(CC) -shared $(CPPFLAGS) $(LDFLAGS) -Wall -o $@ $? + +clean: + rm addpartial-overlay.so diff --git a/contrib/slapd-modules/addpartial/README b/contrib/slapd-modules/addpartial/README new file mode 100644 index 0000000000..dca8b141bd --- /dev/null +++ b/contrib/slapd-modules/addpartial/README @@ -0,0 +1,61 @@ +addpartial Overlay README + +DESCRIPTION + This package contains an OpenLDAP overlay called "addpartial" that + intercepts add requests, determines if the entry exists, determines what + attributes, if any, have changed, and modifies those attributes. If the + entry does not exist, the add request falls through and proceeds normally. + If the entry exists but no changes have been detected, the client receives + LDAP_SUCCESS (I suppose it is debatable what to do in this case, but this is + the most clean for my use. The LDAP_SUCCESS lets me know that the entry I + sent slapd == the entry already in my slapd DB. Perhaps this behavior + should be configurable in the future). + + When a change is found, the addpartial overlay will replace all values for + the attribute (if an attribute does not exist in the new entry but exists + in the entry in the slapd DB, a replace will be done with an empty list of + values). + + Once a modify takes place, the addpartial overlay will write changes to the + replog (using the slap_replog_cb). If you are using syncrepl for + replication, the syncprov overlay will properly process the change, provided + that addpartial is the first overlay to run. Please see the CAVEATS for + more specifics about this. + + The addpartial overlay makes it easy to replicate full entries to a slapd + instance without worrying about the differences between entries or even if + the entry exists. Using ldapadd to add entries, the addpartial overlay can + compare about 500 records per second. The intent of the addpartial overlay + is to make it easy to replicate records from a source that is not an LDAP + instance, such as a database. The overlay is also useful in places where it + is easier to create full entries rather than comparing an entry with an + entry that must be retrieved (with ldapsearch or similar) from an existing + slapd DB to find changes. + + The addpartial overlay has been used in production since August 2004 and has + processed millions of records without incident. + +BUILDING + A Makefile is included, please set your OPENLDAP_SRC directory properly. + +INSTALLATION + After compiling the addpartial overlay, add the following to your + slapd.conf: + + ### slapd.conf + ... + moduleload /path/to/addpartial-overlay.so + ... + # after database directive... + # this overlay should be the last overlay in the config file to ensure that + # it properly intercepts the add request + overlay addpartial + ... + ### end slapd.conf + +CAVEATS + - In order to ensure that addpartial does what it needs to do, it should be + the last overlay configured so it will run before the other overlays. + This is especially important if you are using syncrepl, as the modify that + addpartial does will muck with the locking that takes place in the + syncprov overlay. diff --git a/contrib/slapd-modules/addpartial/addpartial-overlay.c b/contrib/slapd-modules/addpartial/addpartial-overlay.c new file mode 100644 index 0000000000..92100405bd --- /dev/null +++ b/contrib/slapd-modules/addpartial/addpartial-overlay.c @@ -0,0 +1,434 @@ +/** + * $Id: addpartial-overlay.c 5376 2007-01-26 20:03:13Z dhawes $ + * + * Copyright (C) 2004 Virginia Tech, David Hawes. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * http://www.OpenLDAP.org/license.html. + * + * SEE LICENSE FOR MORE INFORMATION + * + * Author: David H. Hawes, Jr. + * Email: dhawes@vt.edu + * Version: $Revision: 5376 $ + * Updated: $Date: 2007-01-26 15:03:13 -0500 (Fri, 26 Jan 2007) $ + * + * addpartial-overlay + * + * This is an OpenLDAP overlay that intercepts ADD requests, determines if a + * change has actually taken place for that record, and then performs a modify + * request for those values that have changed (modified, added, deleted). If + * the record has not changed in any way, it is ignored. If the record does not + * exist, the record falls through to the normal add mechanism. This overlay is + * useful for replicating from sources that are not LDAPs where it is easier to + * build entire records than to determine the changes (i.e. a database). + */ + +#include "portable.h" +#include +#include +#include +#include "slap.h" +#include +#include + +static int addpartial_search_cb( Operation *op, SlapReply *rs); +static int collect_error_msg_cb( Operation *op, SlapReply *rs); + +static slap_overinst addpartial; + +/** + * The meat of the overlay. Search for the record, determine changes, take + * action or fall through. + */ +static int addpartial_add( Operation *op, SlapReply *rs) +{ + Operation nop = *op; + SlapReply nrs = { REP_RESULT }; + Filter *filter = NULL; + Entry *toAdd = NULL; + struct berval fstr = BER_BVNULL; + slap_callback cb = { NULL, addpartial_search_cb, NULL, NULL }; + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + int rc; + + toAdd = op->oq_add.rs_e; + + Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n", + addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0); + + /* if the user doesn't have access, fall through to the normal ADD */ + if(!access_allowed(op, toAdd, slap_schema.si_ad_entry, + NULL, ACL_WRITE, NULL)) + { + return SLAP_CB_CONTINUE; + } + + rs->sr_text = NULL; + + nop.o_callback = &cb; + op->o_bd->bd_info = (BackendInfo *) on->on_info; + nop.o_tag = LDAP_REQ_SEARCH; + nop.o_ctrls = NULL; + + filter = str2filter("(objectclass=*)"); + filter2bv(filter, &fstr); + + nop.ors_scope = LDAP_SCOPE_BASE; + nop.ors_deref = LDAP_DEREF_NEVER; + nop.ors_slimit = -1;//SLAP_NO_LIMIT; + nop.ors_tlimit = -1;//SLAP_NO_LIMIT; + nop.ors_attrsonly = 0; + nop.ors_attrs = slap_anlist_no_attrs; + nop.ors_filter = filter; + nop.ors_filterstr = fstr; + + memset(&nrs, 0, sizeof(nrs)); + nrs.sr_type = REP_RESULT; + nrs.sr_err = LDAP_SUCCESS; + nrs.sr_entry = NULL; + nrs.sr_flags |= REP_ENTRY_MUSTBEFREED; + nrs.sr_text = NULL; + + Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type, + 0,0); + + if(nop.o_bd->be_search) + { + rc = nop.o_bd->be_search(&nop, &nrs); + Debug(LDAP_DEBUG_TRACE, "%s: search performed\n", + addpartial.on_bi.bi_type,0,0); + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n", + addpartial.on_bi.bi_type,0,0); + } + + if(filter) + filter_free(filter); + if(fstr.bv_val) + ch_free(fstr.bv_val); + + if(rc != LDAP_SUCCESS) + return SLAP_CB_CONTINUE; + else + { + Entry *found = NULL; + Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, + 0,0); + found = (Entry *) cb.sc_private; + + if(found) + { + Attribute *attr = NULL; + Attribute *at = NULL; + int ret; + Modifications *mods = NULL; + Modifications **modtail = &mods; + Modifications *mod = NULL; + + Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n", + addpartial.on_bi.bi_type,0,0); + + /* determine if the changes are in the found entry */ + for(attr = toAdd->e_attrs; attr; attr = attr->a_next) + { + if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; + + at = attr_find(found->e_attrs, attr->a_desc); + if(!at) + { + Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val,0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val; + mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + *modtail = mod; + modtail = &mod->sml_next; + } + else + { + MatchingRule *mr = attr->a_desc->ad_type->sat_equality; + struct berval *bv; + const char *text; + int acount , bcount; + Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val,0); + + for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; + bv++, acount++) + { + /* count num values for attr */ + } + for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; + bv++, bcount++) + { + /* count num values for attr */ + } + if(acount != bcount) + { + Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n", + addpartial.on_bi.bi_type, + "replace all",0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val; + mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + *modtail = mod; + modtail = &mod->sml_next; + continue; + } + + for(bv = attr->a_vals; bv->bv_val != NULL; bv++) + { + struct berval *v; + ret = -1; + + for(v = at->a_vals; v->bv_val != NULL; v++) + { + int r; + if(mr && ((r = value_match(&ret, attr->a_desc, mr, + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, + bv, v, &text)) == 0)) + { + if(ret == 0) + break; + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue DNE, r: %d \n", + addpartial.on_bi.bi_type, + r,0); + ret = strcmp(bv->bv_val, v->bv_val); + if(ret == 0) + break; + } + } + + if(ret == 0) + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue %s exists, ret: %d\n", + addpartial.on_bi.bi_type, bv->bv_val, ret); + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: \tvalue %s DNE, ret: %d\n", + addpartial.on_bi.bi_type, bv->bv_val, ret); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + mod->sml_op &= LDAP_MOD_OP; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type.bv_val = + attr->a_desc->ad_cname.bv_val; + mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); + mod->sml_values = attr->a_vals; + mod->sml_nvalues = attr->a_nvals; + *modtail = mod; + modtail = &mod->sml_next; + break; + } + } + } + } + + /* determine if any attributes were deleted */ + for(attr = found->e_attrs; attr; attr = attr->a_next) + { + if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; + + at = NULL; + at = attr_find(toAdd->e_attrs, attr->a_desc); + if(!at) + { + Debug(LDAP_DEBUG_TRACE, + "%s: Attribute %s not found in new entry!!!\n", + addpartial.on_bi.bi_type, + attr->a_desc->ad_cname.bv_val, 0); + mod = (Modifications *) ch_malloc(sizeof( + Modifications)); + mod->sml_flags = 0; + mod->sml_op = LDAP_MOD_REPLACE; + mod->sml_next = NULL; + mod->sml_desc = attr->a_desc; + mod->sml_type.bv_val = + attr->a_desc->ad_cname.bv_val; + mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); + mod->sml_values = NULL; + mod->sml_nvalues = NULL; + *modtail = mod; + modtail = &mod->sml_next; + } + else + { + Debug(LDAP_DEBUG_TRACE, + "%s: Attribute %s found in new entry\n", + addpartial.on_bi.bi_type, + at->a_desc->ad_cname.bv_val, 0); + } + } + + if(mods) + { + Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", + addpartial.on_bi.bi_type, 0, 0); + if(nop.o_bd->be_modify) + { + Modifications *m = NULL; + int modcount; + slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL }; + slap_callback nullcb = { NULL, collect_error_msg_cb, + NULL, NULL }; + char textbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof textbuf; + + memset(&nrs, 0, sizeof(nrs)); + nrs.sr_type = REP_RESULT; + nrs.sr_err = LDAP_SUCCESS; + nrs.sr_entry = NULL; + nrs.sr_text = NULL; + + nop.o_tag = LDAP_REQ_MODIFY; + nop.orm_modlist = mods; + cb2.sc_next = &nullcb; + nop.o_callback = &cb2; + nop.o_bd->bd_info = (BackendInfo *) on->on_info; + + for(m = mods, modcount = 0; m; m = m->sml_next, + modcount++) + { + /* count number of mods */ + } + + Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n", + addpartial.on_bi.bi_type, modcount, 0); + + rc = (nop.o_bd->be_modify)(&nop, &nrs); + + if(rc == LDAP_SUCCESS) + { + Debug(LDAP_DEBUG_TRACE, + "%s: modify successful\n", + addpartial.on_bi.bi_type, 0, 0); + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", + addpartial.on_bi.bi_type, rc, 0); + rs->sr_err = rc; + if(nrs.sr_text) + { + rs->sr_text = nullcb.sc_private; + } + } + + Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", + addpartial.on_bi.bi_type, 0, 0); + + if(mods != NULL) + { + Modifications *toDel; + + for(toDel = mods; toDel; toDel = mods) + { + mods = mods->sml_next; + ch_free(toDel); + } + } + } + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n", + addpartial.on_bi.bi_type, 0, 0); + } + + if(found != NULL) ; + entry_free(found); + } + else + { + Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", + addpartial.on_bi.bi_type, 0, 0); + } + + op->o_callback = NULL; + send_ldap_result( op, rs ); + ch_free((void *)rs->sr_text); + rs->sr_text = NULL; + + return LDAP_SUCCESS; + } +} + +static int addpartial_search_cb( Operation *op, SlapReply *rs) +{ + Entry *entry = NULL; + + if(rs->sr_type != REP_SEARCH) return 0; + + Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n", + addpartial.on_bi.bi_type, 0, 0); + + if(rs->sr_entry) + { + Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n", + addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0); + entry = rs->sr_entry; + op->o_callback->sc_private = (void *) entry_dup(entry); + } + + return 0; +} + +static int collect_error_msg_cb( Operation *op, SlapReply *rs) +{ + if(rs->sr_text) + { + op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text); + } + + return LDAP_SUCCESS; +} + +int addpartial_init() +{ + addpartial.on_bi.bi_type = "addpartial"; + addpartial.on_bi.bi_op_add = addpartial_add; + + return (overlay_register(&addpartial)); +} + +int init_module(int argc, char *argv[]) +{ + return addpartial_init(); +} diff --git a/contrib/slapd-modules/allop/allop.c b/contrib/slapd-modules/allop/allop.c index 6ddf4a473e..e5cbf416be 100644 --- a/contrib/slapd-modules/allop/allop.c +++ b/contrib/slapd-modules/allop/allop.c @@ -39,6 +39,7 @@ allop-URI #include #include "slap.h" +#include "config.h" #define SLAP_OVER_VERSION_REQUIRE(major,minor,patch) \ ( \ @@ -140,7 +141,7 @@ allop_db_config( } static int -allop_db_destroy( BackendDB *be ) +allop_db_destroy( BackendDB *be, ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; allop_t *ao = (allop_t *)on->on_bi.bi_private; diff --git a/contrib/slapd-modules/passwd/radius.c b/contrib/slapd-modules/passwd/radius.c index f4bbb284bb..0e9bb36d1e 100644 --- a/contrib/slapd-modules/passwd/radius.c +++ b/contrib/slapd-modules/passwd/radius.c @@ -12,11 +12,14 @@ * . */ +#include "portable.h" + #include #include #include /* BER_BVC definition */ #include "lutil.h" +#include #include #include @@ -25,6 +28,7 @@ static LUTIL_PASSWD_CHK_FUNC chk_radius; static const struct berval scheme = BER_BVC("{RADIUS}"); static char *config_filename; +static ldap_pvt_thread_mutex_t libradius_mutex; static int chk_radius( @@ -58,8 +62,11 @@ chk_radius( return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ } + ldap_pvt_thread_mutex_lock( &libradius_mutex ); + h = rad_auth_open(); if ( h == NULL ) { + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); return LUTIL_PASSWD_ERR; } @@ -79,16 +86,37 @@ chk_radius( goto done; } - if ( rad_send_request( h ) == RAD_ACCESS_ACCEPT ) { + switch ( rad_send_request( h ) ) { + case RAD_ACCESS_ACCEPT: rc = LUTIL_PASSWD_OK; + break; + + case RAD_ACCESS_REJECT: + rc = LUTIL_PASSWD_ERR; + break; + + case RAD_ACCESS_CHALLENGE: + rc = LUTIL_PASSWD_ERR; + break; + + case -1: + /* no valid response is received */ + break; } done:; rad_close( h ); + ldap_pvt_thread_mutex_unlock( &libradius_mutex ); return rc; } +int +term_module() +{ + return ldap_pvt_thread_mutex_destroy( &libradius_mutex ); +} + int init_module( int argc, char *argv[] ) { @@ -109,5 +137,7 @@ init_module( int argc, char *argv[] ) } } + ldap_pvt_thread_mutex_init( &libradius_mutex ); + return lutil_passwd_add( (struct berval *)&scheme, chk_radius, NULL ); } diff --git a/contrib/slapd-modules/smbk5pwd/smbk5pwd.c b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c index 6b674583eb..dabf6e782a 100644 --- a/contrib/slapd-modules/smbk5pwd/smbk5pwd.c +++ b/contrib/slapd-modules/smbk5pwd/smbk5pwd.c @@ -943,7 +943,7 @@ smbk5pwd_modules_init( smbk5pwd_t *pi ) } static int -smbk5pwd_db_init(BackendDB *be) +smbk5pwd_db_init(BackendDB *be, ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; smbk5pwd_t *pi; @@ -958,7 +958,7 @@ smbk5pwd_db_init(BackendDB *be) } static int -smbk5pwd_db_open(BackendDB *be) +smbk5pwd_db_open(BackendDB *be, ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private; @@ -978,7 +978,7 @@ smbk5pwd_db_open(BackendDB *be) } static int -smbk5pwd_db_destroy(BackendDB *be) +smbk5pwd_db_destroy(BackendDB *be, ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; smbk5pwd_t *pi = (smbk5pwd_t *)on->on_bi.bi_private; diff --git a/doc/devel/toolargs b/doc/devel/toolargs index 24c1482c88..555ce64772 100644 --- a/doc/devel/toolargs +++ b/doc/devel/toolargs @@ -24,4 +24,4 @@ slaptest F d f uv -v verbose --- -$Header$ +$OpenLDAP$ diff --git a/doc/drafts/draft-haripriya-dynamicgroup-xx.txt b/doc/drafts/draft-haripriya-dynamicgroup-xx.txt new file mode 100644 index 0000000000..a68af29a35 --- /dev/null +++ b/doc/drafts/draft-haripriya-dynamicgroup-xx.txt @@ -0,0 +1,1400 @@ + + + +Network Working Group S. Haripriya +Internet-Draft Jaimon. Jose, Ed. +Updates: 02 (if approved) Jim. Sermersheim +Intended status: Standards Track Novell, Inc. +Expires: July 9, 2007 January 5, 2007 + + + LDAP: Dynamic Groups for LDAPv3 + draft-haripriya-dynamicgroup-02 + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on July 9, 2007. + +Copyright Notice + + Copyright (C) The Internet Society (2007). + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 1] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +Abstract + + This document describes the requirements, semantics, schema elements, + and operations needed for a dynamic group feature in LDAP. A dynamic + group is defined here as a group object with a membership list of + distinguished names that is dynamically generated using LDAP search + criteria. The dynamic membership list may then be interrogated by + LDAP search and compare operations, and may also be used to find the + groups that an object is a member of. This feature eliminates a huge + amount of the administrative effort required today for maintaining + group memberships and role-based operations in large enterprises. + + +Table of Contents + + 1. Conventions used in this document . . . . . . . . . . . . . . 4 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 3. Requirements of a dynamic group feature . . . . . . . . . . . 6 + 4. Schema and Semantic Definitions for Dynamic Groups . . . . . . 7 + 4.1. Object Classes . . . . . . . . . . . . . . . . . . . . . . 7 + 4.1.1. dynamicGroup . . . . . . . . . . . . . . . . . . . . . 7 + 4.1.2. dynamicGroupOfUniqueNames . . . . . . . . . . . . . . 7 + 4.1.3. dynamicGroupAux . . . . . . . . . . . . . . . . . . . 7 + 4.1.4. dynamicGroupOfUniqueNamesAux . . . . . . . . . . . . . 7 + 4.2. Attributes . . . . . . . . . . . . . . . . . . . . . . . . 8 + 4.2.1. memberQueryURL . . . . . . . . . . . . . . . . . . . . 8 + 4.2.2. excludedMember . . . . . . . . . . . . . . . . . . . . 11 + 4.3. member . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 4.4. uniqueMember . . . . . . . . . . . . . . . . . . . . . . . 11 + 4.5. dgIdentity . . . . . . . . . . . . . . . . . . . . . . . . 11 + 4.5.1. dgIdentity - Security implications . . . . . . . . . . 12 + 5. Advertisement of support for dynamic groups . . . . . . . . . 13 + 6. Dynamic Group Operations . . . . . . . . . . . . . . . . . . . 14 + 6.1. Existing Operations . . . . . . . . . . . . . . . . . . . 14 + 6.1.1. Access to resources in the directory . . . . . . . . . 14 + 6.1.2. Reading a dynamic group object . . . . . . . . . . . . 14 + 6.1.3. 'Is Member Of' functionality . . . . . . . . . . . . . 15 + 6.2. New Extensions . . . . . . . . . . . . . . . . . . . . . . 16 + 6.2.1. Managing the static members of a dynamic group . . . . 16 + 7. Performance Considerations . . . . . . . . . . . . . . . . . . 17 + 7.1. Caching of Dynamic Members . . . . . . . . . . . . . . . . 17 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 18 + 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 19 + 10. Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . 20 + 11. Normative References . . . . . . . . . . . . . . . . . . . . . 21 + Appendix A. Example Values for memberQueryURL . . . . . . . . . . 22 + Appendix B. Acknowledgments . . . . . . . . . . . . . . . . . . . 23 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 24 + + + +Haripriya, et al. Expires July 9, 2007 [Page 2] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + + Intellectual Property and Copyright Statements . . . . . . . . . . 25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 3] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +1. Conventions used in this document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [1]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 4] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +2. Introduction + + The LDAP schema described in [4] defines two object classes: + 'groupOfNames', and 'groupOfUniqueNames', that hold a static list of + distinguished names in their 'member' or 'uniqueMember' attributes + respectively, and are typically used to describe a group of objects + for various functions. These grouping functions range from simple + group membership applications such as email distribution lists to + describing common authorization for a set of users The administration + and updating of these membership lists must be done by specifically + modifying the DN values in the member or uniqueMember attributes. + Thus, each time a change in membership happens, a process must exist + which adds or removes the particular entry's DN from the member + attribute. For example, consider an organization, where the access + to its facilities is controlled by membership in a directory group. + Assume that all employees in a department have been added to the + group that provides access to the required department facility. If + an employee moves from one department to another, the administrator + must remove the employee from one group and add him to another. + Similarly consider an organization that wants to provide access to + its facility, to both interns and employees on weekdays, but only to + employees on weekends. It would be effort-consuming to achieve this + with static groups. + + "Dynamic groups" are like normal groups, but they let one specify + criteria to be used for evaluating membership to a group; the + membership of the group is determined dynamically by the directory + servers involved. This lets the group administrator define the + membership in terms of attributes, and let the DSAs worry about who + are the actual members. This solution is more scalable and reduces + administrative costs. This can also supplement static groups in LDAP + to provide flexibility to the user. + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 5] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +3. Requirements of a dynamic group feature + + The following requirements SHOULD be met by a proposal for the + dynamic groups feature: + + 1. Creation and administration of dynamic groups should be done + using normal LDAP operations. + + 2. Applications must be able to use dynamic groups in the same way + that they are able to use static groups for listing members and + for membership evaluation. + + 3. Interrogation of a dynamic group's membership should be done + using normal LDAP operations, and should be consistent. This + means that all authorization identities with the same permission + to the membership attribute of a dynamic group (such as 'read') + should be presented with the same membership list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 6] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +4. Schema and Semantic Definitions for Dynamic Groups + + The dynamic group classes are defined by the following schema + +4.1. Object Classes + + The following object classes MUST be supported, and their semantics + understood by the server, for it to support the dynamic groups + feature. + +4.1.1. dynamicGroup + + ( NAME 'dynamicGroup' SUP groupOfNames STRUCTURAL MAY + (memberQueryURL $ excludedMember $ dgIdentity )) + + This structural object class is used to create a dynamic group + object. It is derived from groupOfNames, which is defined in [4]. + +4.1.2. dynamicGroupOfUniqueNames + + ( NAME 'dynamicGroupOfUniqueNames' SUP groupOfUniqueNames + STRUCTURAL MAY (memberQueryURL $ excludedMember $ dgIdentity )) + + This structural object class is used to create a dynamic group object + whose membership list is held in a uniqueMember attribute. It is + derived from groupOfUniqueNames, which is defined in [4]. + +4.1.3. dynamicGroupAux + + ( NAME 'dynamicGroupAux' SUP groupOfNames AUXILIARY MAY + (memberQueryURL $ excludedMember $ dgIdentity )) + + This auxiliary object class is used to convert an existing object to + a dynamic group or to create an object of another object class but + with dynamic group capabilities. This is derived from groupOfNames + which is defined in [4]. + +4.1.4. dynamicGroupOfUniqueNamesAux + + ( NAME 'dynamicGroupOfUniqueNamesAux' SUP groupOfUniqueNames + AUXILIARY MAY (memberQueryURL $ excludedMember $ dgIdentity )) + + This auxiliary object class is used to convert an existing object to + a dynamic group of unique names or to create an object of another + object class but with dynamic group capabilities. This is derived + from groupOfUniqueNames which is defined in [4]. + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 7] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +4.2. Attributes + + The following attribute names MUST be supported by the server. + +4.2.1. memberQueryURL + + This attribute describes the membership of the list using an LDAPURL + [3]. + + ( NAME 'memberQueryURL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + The value of memberQueryURL is encoded as an LDAPURL [3] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 8] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + + The BNF from [3] is listed here for reference. +ldapurl = scheme COLON SLASH SLASH [host [COLON port]] [SLASH dn + [QUESTION [attributes] [QUESTION [scope] [QUESTION [filter] [QUESTION + extensions]]]]] + ; and are defined + ; in Sections 3.2.2 and 3.2.3 + ; of [RFC3986]. + ; is from Section 3 of + ; [RFC4515], subject to the + ; provisions of the + ; "Percent-Encoding" section + ; below. +scheme = "ldap" +dn = distinguishedName ; From Section 3 of [RFC4514], + ; subject to the provisions of + ; the "Percent-Encoding" + ; section below. +attributes = attrdesc *(COMMA attrdesc) +attrdesc = selector *(COMMA selector) +selector = attributeSelector ; From Section 4.5.1 of + ; [RFC4511], subject to the + ; provisions of the + ; "Percent-Encoding" section + ; below. +scope = "base" / "one" / "sub" +extensions = extension *(COMMA extension) +extension = [EXCLAMATION] extype [EQUALS exvalue] +extype = oid ; From section 1.4 of [RFC4512]. +exvalue = LDAPString ; From section 4.1.2 of + ; [RFC4511], subject to the + ; provisions of the + ; "Percent-Encoding" section + ; below. +EXCLAMATION = %x21 ; exclamation mark ("!") +SLASH = %x2F ; forward slash ("/") +COLON = %x3A ; colon (":") +QUESTION = %x3F ; question mark ("?") + + + For the purpose of evaluating dynamic members, the directory server + uses only the dn, scope, filter and extensions fields. All remaining + fields are ignored if specified. If other fields are specified, the + server SHALL ignore them and MAY omit them when presenting the value + to a client. The dn is used to specify the base dn from which to + start the search for dynamic members. The scope specifies the scope + with respect to the dn in which to search for dynamic members. The + filter specifies the criteria with which to select objects for + dynamic membership. + + + +Haripriya, et al. Expires July 9, 2007 [Page 9] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +4.2.1.1. The x-chain extension + + A new extension is defined for use of the memberQueryURL in dynamic + groups, named 'x-chain'. x-chain does not take a value. When x-chain + is present, the server must follow any search continuation references + to other servers while searching for dynamic members. When x-chain + is absent, the dynamic members computed will be only those that are + present on the server from which the search is made. A directory + server supporting the memberQueryURL MAY support the x-chain + extension, thus the x-chain extension could be critical or non- + critical as specified by the '!' prefix to the extension type. + +4.2.1.2. Semantics of multiple values for memberQueryURL + + The memberQueryURL MAY have multiple values, and in that case, the + members of the dynamic group will be the union of the members + computed using each individual URL value. This is useful in + specifying a group membership that is made up from subtrees rooted at + different base DNs, and possibly using different filters. + +4.2.1.3. Condition of membership + + An object O is a member of a dynamic group G if and only if + + (( O is a value of the 'member' or 'uniqueMember' attribute of G) + + OR + + (( O is selected by the membership criteria specified in the + 'memberQueryURL' attribute values of G) + + AND + + ( O is not listed in the 'excludedMember' attribute of G) )) + + If a member M of a dynamic group G happens to be a dynamic or a + static group, the static or dynamic members of M SHALL NOT be + considered as members of G. M is a member of G though. + + The last condition is imposed because + + o Recursively evaluating members of members may degrade the + performance of the server drastically. + + o Looping may occur particularly in situations where the search + chains across multiple-servers. + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 10] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + + o Dynamic membership assertions (compare operation) cannot be + optimized if recursive memberships are allowed. Without + recursion, comparisons can be made light-weight. + +4.2.2. excludedMember + + ( NAME 'excludedMember' SUP distinguishedName ) + + This attribute is used to exclude entries from being a dynamic member + of a dynamic group. Thus an entry is a dynamic member of a dynamic + group if and only if it is selected by the member criteria specified + by the 'memberQueryURL' attribute or explicitly added to the member + or uniqueMember attribute, and it is not listed in the + 'excludedMember' attribute. + +4.3. member + + ( 2.5.4.31 NAME 'member' SUP distinguishedName ) + + Defined in [4], this attribute is overloaded when used in the context + of a dynamic group. It is used to explicitly specify static members + of a dynamic group. If the same entry is listed in both the 'member' + and 'excludedMember' attributes, the 'member' overrides the + 'excludedMember', and the entry is considered to be a member of the + group. This attribute is also used to interrogate both the static + and dynamic member values of a dynamic group object. Subclasses of + this attribute are NOT considered in this manner. + +4.4. uniqueMember + + ( 2.5.4.32 NAME 'uniqueMember' SUP distinguishedName ) + + Defined in [4], this attribute is overloaded when used in the context + of a dynamic group. It is used to specify the static members of a + dynamic group. If the same entry is listed in both the + 'uniqueMember' and 'excludedMember' attributes, the 'uniqueMember' + overrides the 'excludedMember', and the entry is considered to be a + member of the group. This attribute is also used to interrogate both + the static and dynamic member values of a dynamic group object. + Subclasses of this attribute are NOT considered in this manner. + +4.5. dgIdentity + + ( NAME 'identity' SUP distinguishedName SINGLE-VALUE ) + + In order to provide consistent results when processing the search + criteria, the server must use a single authorization identity. If + the authorization of the bound identity is used, the membership list + + + +Haripriya, et al. Expires July 9, 2007 [Page 11] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + + will vary, from identity to identity due to differing access + controls. This may either be done by the server authenticating as + the dgIdentity prior to performing a search or compare operation, or + may be done by simply assuming the authorization of the dgIdentity + when performing those operations. As server implementations vary, so + may the mechanisms to achieve consistent results through the use of + the dgIdentity. In the case that the server authenticates as the + dgIdentity, it may be required by the server that this identity have + proper authentication credentials, and it may be required that this + identity reside in the DIB of the local server. + + In the absence of an identity value, or in case the identity value + cannot be used, the server will process the memberQueryURL as the + anonymous identity. This attribute MAY be supported, and represents + the identity the server will use for processing the memberQueryURL. + +4.5.1. dgIdentity - Security implications + + Because this attribute indirectly but effectively grants anyone with + read or compare access to the member or uniqueMember attribute + sufficient permission to gain a DN result set from the + memberQueryURL, server implementations SHOULD NOT allow this + attribute to be populated with the DN of any object that is not + administered by the identity making the change to this attribute. + For purposes of this document, to "administer an object" indicates + that the administrative identity has the ability to fully update the + access control mechanism in place the object in question. As of this + writing, there is no way to describe further what it means to be + fully able to administer the access control mechanism for an object, + so this definition is left as implementation-specific. + + This requirement will allow an entity that has privileges to + administer a particular subtree (meaning that entity can add, delete, + and update objects in that subtree), to place in the dgIdentity DNs + of only those objects it administers. + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 12] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +5. Advertisement of support for dynamic groups + + If the dynamic groups schema is not present on an LDAP server, it + MUST be assumed that the dynamic groups feature is not supported. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 13] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +6. Dynamic Group Operations + +6.1. Existing Operations + + The following operations SHOULD expose the dynamic groups + functionality. These operations do not require any change in the + LDAP protocol to be exchanged between the client and server. + +6.1.1. Access to resources in the directory + + If access control items are set on a target resource object in the + directory, with the subject being a dynamic group object, then all + the members of the group object, including the dynamic members, will + get the same permissions on the target entry. This would be the most + useful application of dynamic groups as seen by an administrator + because it lets the server control access to resources based on + dynamic membership to a trustee (subject of ACI) of the resource. + The way to specify a dynamic ACL is currently implementation + specific, as there is no common ACL definition for LDAP, and hence + will be dealt with in a separate document or later (TO BE DONE). + +6.1.2. Reading a dynamic group object + + When the member attributes of a dynamic group object is listed by the + client using an LDAP search operation, the member values returned + SHOULD contain both the static and dynamic members of the group + object. This functionality will not require a change to the + protocol, and the clients need not be aware of dynamic groups to + exploit this functionality. This feature is useful for clients that + determine access privileges to a resource by themselves, by reading + the members of a group object. It will also be useful to + administrators who want to see the result of the query URL that they + set on the dynamic group entry. Note that this overloads the + semantics of the 'member' and 'uniqueMember' attributes. This could + lead to some surprises for the client . + + for example: Clients that read the member attribute of a dynamic + group object and then attempt to remove values (which were dynamic) + could get an error specifying such a value was not there. + + Example: + + Let cn=dg1,o=myorg be a dynamic group object with the following + attributes stored in the directory. + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 14] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + + member: cn=admin,o=myorg + + excludedMember: cn=guest,ou=finance,o=myorg + + excludedMember: cn=robin,ou=finance,o=myorg + + memberQueryURL: + ldap:///ou=finance,o=myorg??sub?(objectclass=organizationalPerson) + + If there are 5 organizationalPerson objects under ou=finance,o=myorg + with common names bob, alice, john, robin, and guest, then the output + of a base-scope LDAP search at cn=dg1,o=myorg, with the attribute + list containing 'member' will be as follows: + + dn: cn=dg1,o=myorg + + member: cn=admin,o=myorg + + member: cn=bob,ou=finance,o=myorg + + member: cn=alice,ou=finance,o=myorg + + member: cn=john,ou=finance,o=myorg + +6.1.3. 'Is Member Of' functionality + + The LDAP compare operation allows one to discover whether a given DN + is in the membership list of a dynamic group. Again, the server + SHOULD produce consistent results among different authorization + identities when processing this request, as long as those identities + have the same access to the member or uniqueMember attribute. Using + the data from the example in Section 6.1.2, a compare on + cn=dg1,o=myorg, for the AVA member=cn=bob,ou=finance,o=myorg would + result in a response of compareTrue (assuming the bound identity was + authorized to compare the member attribute of cn=dg1,o=myorg). + + Likewise, a search operation that contains an equalityMatch or + presence filter, naming the member or uniqueMember attribute as the + attribute (such as (member= cn=bob,ou=finance,o=myorg), or + (member=*)), will cause the server to evaluate this filter against + the rules given in Section 4.2.1.3 in the event that the search is + performed on a dynamic group object. As of this writing, no other + matching rules exist for the distinguished name syntax, thus no + requirements beyond equalityMatch are given here. + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 15] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +6.2. New Extensions + + The following new extensions are added for dynamic group support. + +6.2.1. Managing the static members of a dynamic group + + Because a dynamic group overloads the semantics of the member and + uniqueMember attributes, a mechanism is needed to retrieve the static + values found in these attributes for management purposes. To serve + this need, a new attribute option is defined here called 'x-static'. + Attribute options are discussed in Section 2.5 of [2]. This option + SHALL only be specified with the 'member' or 'uniqueMember' + attribute. When the LDAP server does not understand the semantics of + this option on a given attribute, the option SHOULD be ignored. This + attribute option is only used to affect the transmitted values, and + does not impose sub-typing semantics on the attribute. + + This option MAY be specified by a client during a search request in + the list of attributes to be returned, i.e. member;x-static. In this + case, the server SHALL only return those members of the dynamic group + that are statically listed as values of the member or uniqueMember + attribute. The evaluation process listed in Section 9 SHALL NOT be + used to populate the values to be returned. + + This option MAY be specified is either an equalityMatch or presence + search filter. In this case, the server evaluates only the values + statically listed in the member or uniqueMember attribute, and does + not apply the evaluation process listed in Section 9. + + This option MAY be specified in update operations such as add and + modify, but SHOULD be ignored, as its presence is semantically the + same as its non-presence. + + Note to user: Performing a search to read a dynamic group, with a + filter item such as (member=*), and specifying member;x-static, may + result in a search result entry that has no member attribute. This + may seem counter-intuitive. + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 16] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +7. Performance Considerations + + When the x-chain extension is present on the memberQueryURL, the + server MUST follow any search continuation references to other + servers while searching for dynamic members. This may be expensive + and slow in a true distributed environment. The dynamicGroup + implementation can consider a distributed caching feature to improve + the performance. An outline of such a distributed caching is given + below. + +7.1. Caching of Dynamic Members + + Since the dynamic members of a group are computed every time the + group is accessed, the performance could be affected. An + implementation of dynamic groups can get around this problem by + caching the computed members of a dynamic group locally and using the + cached data subsequently. One way to do this is to create pseudo- + objects for each dynamic group on every server that holds an object + that is a dynamic member of the group. With this, the computation of + the dynamic members of a group reduces to the task of reading the + pseudo-objects from each server. These pseudo-objects need to be + linked from the original dynamic group to speed up the member + computation. Also, since these are cached objects, appropriate + timeouts need to be associated with the cache after which the cache + should be invalidated or refreshed + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 17] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +8. Security Considerations + + This document discusses the use of one object as the identity + (Section 4.5) with which to read information for another object. If + the creation of the dgIdentity attribute is uncontrolled, an intruder + could potentially create a dynamic group with the identity of, say, + the administrator, to be able to read the directory as the + administrator, and see information which would be otherwise + unavailable to him. Thus, a person adding an object as identity of a + dynamic group should have appropriate permissions on the object being + added as identity. + + This document also discusses using dynamic memberships to provide + access for resources in a directory. As the dynamic members are not + created by the administrator, there could be surprises for the + administrator in the form of certain objects getting access to + certain resources through dynamic membership, which the administrator + never intended. So the administrator should be wary of such + problems. The administrator could view the memberships and make sure + that anybody who is not supposed to be a member of a group is added + to the excludedMember list. + + Denial of service attacks can be launched on an LDAP server, by + repeatedly searching for a dynamic group with a large membership list + and listing the member attribute. A more effective form of denial of + service attack could be launched by making searches of the form + (member="somedn") at the top of tree and closing the client + connection as soon as the search starts. Some administrative limits + be imposed to avoid such situations. + + The dynamic groups feature could be potentially misused by a user to + circumvent any administrative size-limit restriction placed on the + server. In order to search an LDAP server and obtain the names of + all the objects on the server irrespective of admin size-limit + restriction on the server, the LDAP user could create a dynamic group + with a memberQueryURL which matches all objects in the tree, and list + just that one object. + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 18] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +9. IANA Considerations + + There are no IANA considerations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 19] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +10. Conclusions + + This document discusses the syntax, semantics and usage of dynamic + groups in LDAPv3. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 20] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +11. Normative References + + [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [2] Zeilenga, K., "Lightweight Directory Access Protocol (LDAP): + Directory Information Models", RFC 4512, June 2006. + + [3] Smith, M. and T. Howes, "Lightweight Directory Access Protocol + (LDAP): Uniform Resource Locator", RFC 4516, June 2006. + + [4] Sciberras, A., "Lightweight Directory Access Protocol (LDAP): + Schema for User Applications", RFC 4519, June 2006. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 21] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +Appendix A. Example Values for memberQueryURL + + 1. This memberQueryURL value specifies the membership criteria for a + dynamic group entry as "all inetorgperson entries that also have + their title attribute set to 'manager', and are in the DIT-wide + subtree under ou=hr,o=myorg ". + + memberQueryURL: ldap:/// + ou=hr,o=myorg??sub?(& + (objectclass=inetorgperson)(title=manager))? x-chain + + 2. This value lets the user specify the membership criteria for a + dynamic group entry as "all entries on the local server, that + either have unix accounts or belong to the unix department, and + are under the engineering container ". + + memberQueryURL: ldap:///ou=eng,o=myorg??sub? + (|(objectclass=posixaccount)(department=unix)) + + 3. These values let the user specify the membership criteria as "all + inetorgperson entries on the local server, in either the + ou=eng,o=myorg or ou=support,o=myorg" subtrees. + + memberQueryURL: + ldap:///ou=eng,o=myorg??sub?(objectclass=inetorgperson) + + memberQueryURL: + ldap:///ou=support,o=myorg??sub?(objectclass=inetorgperson) + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 22] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +Appendix B. Acknowledgments + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 23] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +Authors' Addresses + + Haripriya S + Novell, Inc. + 49/1 & 49/3 Garvebhavi Palya, + 7th Mile, Hosur Road + Bangalore, Karnataka 560068 + India + + Email: sharipriya@novell.com + + + Jaimon Jose (editor) + Novell, Inc. + 49/1 & 49/3 Garvebhavi Palya, + 7th Mile, Hosur Road + Bangalore, Karnataka 560068 + India + + Email: jjaimon@novell.com + + + Jim Sermersheim + Novell, Inc. + 1800 South Novell Place + Provo, Utah 84606 + US + + Email: jimse@novell.com + + + + + + + + + + + + + + + + + + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 24] + +Internet-Draft LDAP: Dynamic Groups for LDAPv3 January 2007 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Acknowledgment + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + +Haripriya, et al. Expires July 9, 2007 [Page 25] + diff --git a/doc/drafts/draft-wahl-ldap-session-xx.txt b/doc/drafts/draft-wahl-ldap-session-xx.txt new file mode 100644 index 0000000000..ba1c7326d7 --- /dev/null +++ b/doc/drafts/draft-wahl-ldap-session-xx.txt @@ -0,0 +1,1120 @@ + + + +Network Working Group M. Wahl +Internet-Draft Informed Control Inc. +Intended status: Standards Track May 9, 2007 +Expires: November 10, 2007 + + + LDAP Session Tracking Control + draft-wahl-ldap-session-03 + +Status of this Memo + + By submitting this Internet-Draft, each author represents that any + applicable patent or other IPR claims of which he or she is aware + have been or will be disclosed, and any of which he or she becomes + aware will be disclosed, in accordance with Section 6 of BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt. + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + This Internet-Draft will expire on November 10, 2007. + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 1] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +Abstract + + Many network devices, application servers, and middleware components + of a enterprise software infrastructure generate some form of session + tracking identifiers, which are useful when analyzing activity and + accounting logs to group activity relating to a particular session. + This document discusses how Lightweight Directory Access Protocol + version 3 (LDAP) clients can include session tracking identifiers + with their LDAP requests. This information is provided through + controls in the requests the clients send to LDAP servers. The LDAP + server receiving these controls can include the session tracking + identifiers in the log messages it writes, enabling LDAP requests in + the LDAP server's logs to be correlated with activity in logs of + other components in the infrastructure. The control also enables + session tracking information to be generated by LDAP servers and + returned to clients and other servers. Three formats of session + tracking identifiers are defined in this document. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 2] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +1. Introduction + + The majority of directory server implementations produce access logs + detailing each request they receive. These logs can be read using + log parsing tools or specialized log viewer applications. Typically + it will be possible, for each request logged by a directory server, + to determine the bind DN (or possibly another form of authentication + identity) of the client which sent the request to the server, and + many servers also log the IP address of the client that sent the + request. + + In the original OSI architecture, it was envisaged that users might + interact with a directory service through specialized applications, + known as Directory User Agents, which were the clients of the + Directory Access Protocol. Similarly, in early Internet directory + deployments, a majority of LDAP clients were desktop applications, + that used the LDAP protocol to search an enterprise directory for + address book/contact information. + + Today, the majority of LDAP clients are embedded within middleware + and server applications. Legacy address book protocols might be + gatewayed into LDAP, or a server might consult an LDAP server in + order to check a user's password or obtain their preferences. While + the LDAP requests might result from a user's activity somewhere on + the network, it is rare for the user to be 'driving' the LDAP client, + and in most cases the user performing the activity is unaware that + LDAP requests are being generated on their behalf. + + However, this information is important to directory system + administrators and auditors. They may wish to determine who is + making use of the directory service, or track the source of unusual + requests. + + When a directory server administrator reviews a log file produced by + a directory server that has been accessed only by clients that are + themselves middleware, where the end user does not interact with the + middleware directly, only through other kinds of servers (e.g. + application servers or remote access servers), it will be difficult + to correlate between the directory server's log and the logs of the + servers which made use of this directory to determine why the LDAP + requests were made and who were responsible for causing them. + + Reasons for this include: + + o Directory servers are capable of performing many hundreds of + requests per second or more, and even with time synchronization + between the systems on which the directory server and middleware + are deployed, times of requests might not be logged accurately + + + +Wahl Expires November 10, 2007 [Page 3] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + enough to be able to correlate based on time: the server's logs + might be only to 1-second resolution. + + o A single function on a middleware server, such as "authenticate a + user", may result in multiple LDAP requests being generated in + order to perform that request. + + o Many high performance middleware servers implement connection + pooling, managing a set of persistent connections to each + directory server and multiplexing operations across the + connections. Each connection will have the same source IP address + and bind DN. If a particular activity causes multiple LDAP + requests to be generated, each LDAP request might be sent on a + different connection. Also, as LDAP is an asynchronous protocol, + middleware servers may have more than one request in progress on + each connection, asynchronously sending requests to the directory + server on each connection and processing the responses in whatever + order they are received. + + This document defines a new control for use in LDAPv3 [1] operation + requests. This control contains session tracking information that + can be used to correlate log information present in the directory + server's log with the logs of other middleware servers. + + The words "MUST", "SHOULD" and "MAY" are used as defined in RFC 2119 + [2]. + +1.1. Motivation for session tracking + + A typical enterprise deployment with an application indirectly + relying upon the directory might resemble: + + + +------+ +--------+ +----------+ +--------+ + | User | | Appli- | | Auth./ | LDAP | LDAP | + | +-----+ cation +-------+ Identity +------+ Server | + | | | Server | | Provider | | | + | A | | B | | C | | D | + +------+ +--------+ +----------+ +--------+ + + + In this diagram, a user (A) makes some request of an application + server (B). The application server might rely on an integrated or + external authentication provider in order to check the user's + authentication credentials, or might use an identity provider to + obtain profile information about the user. This request might be + made through an API or a protocol other than LDAP, e.g. RADIUS, + Kerberos, SMB, etc. The authentication/identity provider (C) would + + + +Wahl Expires November 10, 2007 [Page 4] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + generate one or more LDAP requests and send them to an LDAP server + (D). + + The LDAP server has the following information already available to it + through the LDAP protocol: the IP address and authentication + credentials of the authentication/identity provider (C). If the + provider has included the Proxy Authorization Control [11], then the + LDAP server might also receive the Distinguished Name or + authorization identity of either the user (A) or the application + server (B), depending on how the authentication/identity provider (C) + uses the directory. In order to obtain this distinguished name + however, the authentication/identity provider (C) might need to + perform one or more LDAP search or bind requests. If there is no + entry in the directory corresponding to the identity of the user (A) + or the application server (B), then there is no way in the base LDAP + specification or the Proxy Authorization Control for the + authentication/identity provider (C) to describe the user (A) or the + application server (B) to the LDAP server (D). + + If either the application server (B) or the authentication/identity + provider (C) have generated a session identifier for tracking the + interactions of the user (A) for a particular session, then it is + useful to include this information with the requests made to the + directory server, so that this session identifier will show up in the + directory server's logs. That is the purpose of the control defined + in the next section. + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 5] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +2. Control definition + + There is currently no standard way of describing a session: there are + many different formats for a session identifier, and each application + that tracks sessions typically has its own semantics for what a + session means. Thus, a control is defined using an extensible model, + in order to incorporate many different application's concepts and + formats of a session tracking identifier. + + The value of the session identifier control encapsulates the + following four pieces of information: sessionSourceIp, + sessionSourceName, formatOID and sessionTrackingIdentifier. + + The sessionSourceIp field is a US-ASCII string encoding of an IPv4 or + IPv6 [3] address of the component of the system which has generated a + session tracking identifier. The purpose of this field is to enable + the directory server administrator, even if they do not have a log + parser that understands a particular session tracking identifier + format, to at least be able to identify the server that manages the + session. Note that there is no guarantee of IP-level connectivity + between the directory server and the system which generated the + tracking identifier, and if Network Address Translation is being + used, the IP address in this field might be from a private use + address range. + + The sessionSourceName field is a UTF-8 [4] encoded ISO 10646 [5] text + string. This field describes the component of the system which has + generated a session tracking identifier. The format of this field is + determined by the formatOID (discussed below); examples of contents + of a sessionSourceName field might be a hostname, a distinguished + name, or a web service address. This contents of this field is not + intended to identify an end user; instead it identifies the server + using a name other than the server's IP address. + + The formatOID is a US-ASCII encoded dotted decimal representation of + an OBJECT IDENTIFIER. The OBJECT IDENTIFIER indicates the scheme + that is used to generate the sessionSourceName and + sessionTrackingIdentifier fields. As there is currently no standard + scheme for session information, it is expected that there will be + many different formats carried within this control. The OBJECT + IDENTIFIERs for three formats are presented in this document. + + The sessionTrackingIdentifier field is a UTF-8 encoded ISO 10646 + string. The session identifier SHOULD be limited to whitespace and + printable characters; non-printing and control characters SHOULD NOT + be used, and byte sequences that are not legal UTF-8 MUST NOT be + used. The syntax of the session identifier and its semantics (e.g., + how values are compared for equality) are governed by the formatOID. + + + +Wahl Expires November 10, 2007 [Page 6] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + For example, the session identifier might be a simple string encoding + of a decimal counter, a username, a timestamp, a fragment of XML, or + it might be something else, depending on the format. + +2.1. Formal definition + + This document defines a single LDAP control. + + The controlType is 1.3.6.1.4.1.21008.108.63.1, the criticality MUST + be either FALSE or absent, and the controlValue MUST be present. The + controlValue OCTET STRING is always present and contains the bytes of + the BER [6] encoding of a value of the ASN.1 data type + SessionIdentifierControlValue, defined as follows: + + LDAP-Session-Identifier-Control + DEFINITIONS IMPLICIT TAGS ::= + BEGIN + + LDAPString ::= OCTET STRING -- UTF-8 encoded + LDAPOID ::= OCTET STRING -- Constrained to numericoid + + SessionIdentifierControlValue ::= SEQUENCE { + sessionSourceIp LDAPString, + sessionSourceName LDAPString, + formatOID LDAPOID, + sessionTrackingIdentifier LDAPString + } + + END + + The sessionSourceIp element SHOULD NOT be longer than 42 characters + (the length necessary for a string representation of an IPv6 + address), and MUST NOT be longer than 128 characters. Each character + will be encoded into a single byte. If the IP address of the system + which generated the session tracking identifier is not known, the + sessionSourceIp element SHOULD be of zero length. + + The sessionSourceName element SHOULD NOT be longer than 1024 + characters, and MUST NOT be longer than 65536 bytes. Note that in + the UTF-8 encoding a character MAY be encoded into more than one + byte. If no other addressing information about that system is known + or relevant to the format, the sessionSourceName element SHOULD be of + zero length. + + The formatOID element MUST contain only the US-ASCII encodings of the + ISO 10646 characters FULL STOP and DIGIT ZERO through DIGIT NINE + (0x2E, 0x30-0x39). The formatOID element MUST NOT be of zero length, + and SHOULD NOT be longer than 1024 characters. + + + +Wahl Expires November 10, 2007 [Page 7] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + The sessionTrackingIdentifier field MAY be of zero length (although + this might not be useful). There is no upper bound on the + sessionTrackingIdentifier, but it is suggested that values SHOULD NOT + be longer than 65536 characters without prior agreement with the + directory server administrator. Note that in the UTF-8 encoding a + character MAY be encoded into more than one byte. + +2.2. Use in LDAP + + The control MAY be included in any LDAP operation. The control has + order-dependent semantics. + + A client might place the control on a message with a bindRequest, + searchRequest, modifyRequest, addRequest, delRequest, modDNRequest, + compareRequest or extendedReq. A client MAY include multiple + controls of this type in a single request. This enables the client + to incorporate multiple distinct session tracking identifiers with + different formats. + + When a network service is proxying or chaining LDAP, in which the + service receives an incoming LDAP request from a client and from this + generates one or more requests to other LDAP servers, the service + SHOULD include any controls of this type that it received from + clients in requests it generates, without modification. A service + MAY silently remove a control if that control would violate security + policy. If the service has its own session state identifier, it + SHOULD include the session identifier control it generates in the + Controls SEQUENCE after any session identifier controls received by + clients. (If there are multiple proxies involved, each will add + their own session state to the end of the controls list). + + A server might place the control on message with a bindResponse, + searchResDone, modifyResponse, addResponse, delResponse, + modDNResponse, compareResponse, extendedResp or intermediateResponse. + The server can include the control in the response regardless of + whether the client included a control in the request or not. (The + control in a response is unsolicited, and a client which does not + recognize the control or a session tracking format can safely ignore + the control, as discussed in the following section). A server MAY + include multiple controls of this type in a response. + +2.3. Extensibility considerations + + The following section of this document defines 3 possible formats, + and it is expected that applications MAY define their own formats to + represent session tracking identifiers already implemented. + + An application developer or server developer who wishes to transfer + + + +Wahl Expires November 10, 2007 [Page 8] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + their implementation's format for session tracking identifier within + an LDAP control MUST choose a new, unique, OBJECT IDENTIFIER to + represent this format. + + The format determines the semantics of the sessionSourceName string, + and the sessionTrackingIdentifier string. + + In general, when an LDAP server that has session tracking logging + enabled receives one or more of these controls with a request, the + server SHOULD include all fields of all of the controls with the + logging information for the request. + + A LDAP server that supports third-party or extensible log parsing + tools SHOULD NOT reject or ignore a control if the formatOID value is + not recognized, as it is expected that applications may include + session tracking identifiers and want to make this information + available to log parsers for correlation purposes, even if the + directory server does not need to make any use of this information. + + However, if the LDAP server does not recognize the control, the + control is not properly formatted, or the LDAP client is not + authorized to use this control, the LDAP server SHOULD ignore the + control and process the request as if the control had not been + included. + + When an LDAP client receives a response that includes this control, + the behavior depends on the client implementation. Clients SHOULD + silently ignore controls with formats they do not recognize, and + process the response as if the control had not been included. + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 9] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +3. Session tracking format definitions + + This section defines three session tracking formats that can be used + within the session tracking control: two for RADIUS accounting, and + one based on usernames. Other formats can be defined in other + documents. + +3.1. Formats for use with RADIUS accounting + + This section defines two possible session tracking formats, that can + be used in LDAP clients that are part of or used by RADIUS servers + [7]. + + With formatOID set to 1.3.6.1.4.1.21008.108.63.1.1 within the control + value, the sessionTrackingIdentifier SHOULD contain the value of the + Acct-Session-Id RADIUS attribute (type 44), as defined in RFC 2866 + [8]. (RFC 2866 section 5.5 states that the Acct-Session-Id SHOULD + contain UTF-8 encoded ISO 10646 characters.) + + With formatOID set to 1.3.6.1.4.1.21008.108.63.1.2 within the control + value, the sessionTrackingIdentifier SHOULD contain the value of the + Acct-Multi-Session-Id RADIUS attribute (type 50), as defined in RFC + 2866 [8]. (RFC 2866 section 5.11 states that the + Acct-Multi-Session-Id SHOULD contain UTF-8 encoded ISO 10646 + characters.) + + In both of these two formats, the value of the sessionSourceIp field + SHOULD contain either a string encoding value of the IPv4 address + from the NAS-IP-Address RADIUS attribute (type 4), or a string + encoding of the IPv6 address from the value of the NAS-IPv6-Address + RADIUS attribute (type 95) as defined in RFC 3162 [9]. The value of + the sessionSourceName field SHOULD contain a string encoding the + value of the NAS-Identifier RADIUS attribute (type 32), if present, + or be of zero length if the NAS-Identifier RADIUS attribute was not + provided or was not in a recognized format. + +3.2. Format for username accounting + + This section defines another possible session tracking format that + can be used in LDAP clients that are part of applications which + identify users with simple string usernames. + + With formatOID set to 1.3.6.1.4.1.21008.108.63.1.3 within the control + value, the sessionTrackingIdentifier SHOULD contain a username that + has already been authenticated by the application that is generating + the session. This format SHOULD NOT be used for purported names, + where the application has not verified that the username is valid. + + + + +Wahl Expires November 10, 2007 [Page 10] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + The sessionSourceName field SHOULD contain the hostname where that + application is running, or be of zero length if the hostname is not + known. + + The username SHOULD be a SASL authorization identity string, as + described in section 3.4.1 of RFC 4422 [10]. It is expected that + these usernames are not globally unique, but are only unique within + the context of a particular application or particular enterprise. A + username need not be a distinguished name, and an implementation + receiving a control in this format MUST NOT assume that the contents + of the sessionTrackingIdentifier can be parsed as a distinguished + name. + + A control with this format differs from the Proxied Authorization + Control as defined in RFC 4370 [11], as the presence of this session + identifier control on a request SHOULD NOT influence the directory + server's access control decision of whether or how to perform that + request. + + Note that this format does not provide any information to + differentiate between multiple sessions or periods of interaction by + the same user. It is primarily intended for deployments which merely + need to be able to tie each directory operation to they identity of + the user whose activities caused the operation request to be + generated, even if the user might not even be represented in the + directory where the operations are being performed. + +3.2.1. Example + + For example, if an application server "app.example.com" with IPv4 + address "192.0.2.1" had authenticated an user with name "bloggs", and + then sent a search request to the LDAP directory in order to obtain + some public information on service configuration intending to provide + it to that user, the application might include a session identifier + control. The SessionIdentifierControlValue would have the following + ASN.1 value prior to encoding: + + + { -- SEQUENCE + "192.0.2.1", -- sessionSourceIp + "app.example.com", -- sessionSourceName + "1.3.6.1.4.1.21008.108.63.1.3", -- formatOID + "bloggs" -- sessionTrackingIdentifier + } + + + + + + + +Wahl Expires November 10, 2007 [Page 11] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + The session identifier control would be sent with controlType + 1.3.6.1.4.1.21008.108.63.1, criticality FALSE, and the controlValue + the BER encoding of the SessionIdentifierControlValue. The control + included with the LDAP request would resemble: + + + { -- SEQUENCE + "1.3.6.1.4.1.21008.108.63.1", -- controlType + FALSE, -- criticality + '304204093139322e302e322e31040f6170702e6578616d706c652e636f6d + 041c312e332e362e312e342e312e32313030382e3130382e36332e312e33 + 0406626c6f676773'H -- controlValue + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 12] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +4. Security Considerations + + The session identifier controls used in this document are not + intended as a security control or proxy authentication mechanism, and + SHOULD NOT be used within a directory server to influence the + operation processing behavior. + + Malicious clients might attempt to provide false or misleading + information in directory server logs through the use of this control. + LDAP servers SHOULD implement access checks which limit whether + session identifier information provided by a client is logged. LDAP + servers which implement this control SHOULD permit the administrator + of the directory server to configure that this control is ignored + unless the request containing the control was received from a client + that been authenticated. LDAP servers which implement this control + SHOULD permit the administrator of the directory server to configure + that this control is ignored unless the client is authorized to use + this or related controls, such as the Proxied Authorization Control + [11]. Session identifier information from clients which do not meet + the server's access check requirement SHOULD be silently discarded. + + In some formats, session tracking identifiers may contain personal- + identifiable information, such as usernames or client IP addresses. + Unless data link, network or transport level encryption is being + used, this information might be visible to attackers monitoring the + network segments across which this information is being transmitted. + Implementations of LDAP clients which include this control in + requests sent to directory servers SHOULD support the use of + underlying security services that establish connection + confidentiality before the control is sent, such as a SASL mechanism + that negotiates a security layer, or the Start TLS operation. + + Correlation of activities across multiple servers can enable + administrators and monitoring tools to construct a more accurate + picture of user behavior. In particular, this tracking control could + be used to determine the set of applications and services with which + a particular user has had interactions. Thus, this control would not + be appropriate to deployments intending to anonymize directory + requests. Session formats containing personal identifiable + information SHOULD NOT be used between systems in different + organizations where there is no existing agreement between those + organizations on privacy protection. + + A value of the session tracking control might contain internal IP + addresses, hostnames and other identifiers that reveal the structure + of an enterprise network. A network service that generates its own + sessions SHOULD NOT send a session tracking control to a directory + server that is under different administration or in a different + + + +Wahl Expires November 10, 2007 [Page 13] + +Internet-Draft LDAP Session Tracking Control May 2007 + + + security enclave from itself. A network service that is an LDAP + client and also either receives requests over another protocol that + contains session tracking identifiers or is proxying incoming LDAP + requests SHOULD NOT forward received session tracking identifiers to + a directory server that is under different administration or in a + different security enclave from itself. A packet inspecting firewall + that permits outgoing LDAP requests from an enterprise network SHOULD + silently remove any session tracking controls from requests that are + being sent to directory servers outside of the enterprise network for + which there is not a preexisting policy configured to allow the + session tracking control to be sent to that directory server. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 14] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +5. IANA Considerations + + This control will be registered as follows: + + Subject: Request for LDAP Protocol Mechanism Registration + + Object Identifier: 1.3.6.1.4.1.21008.108.63.1 + + Description: Session Tracking Identifier + + Person & email address to contact for further information: + Mark Wahl + + Usage: Control + + Specification: (I-D) RFC XXXX + + Author/Change Controller: Mark Wahl + + + The OBJECT IDENTIFIER for particular session identifier formats + defined for other applications need not be registered with IANA. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 15] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +6. Acknowledgments + + This control was inspired by conversations with Greg Lavender. Neil + Wilson provided useful feedback on this document. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 16] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +7. References + +7.1. Normative References + + [1] Zeilenga, K., "Lightweight Directory Access Protocol (LDAP): + Technical Specification Road Map", RFC 4510, June 2006. + + [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", RFC 2119, BCP 14, March 1997. + + [3] Hinden, R., "IP Version 6 Addressing Architecture", RFC 1884, + January 1996. + + [4] Yergeau, F., "UTF-8, a transformation format of ISO 10646", + RFC 3629, November 2003. + + [5] "Universal Multiple-Octet Coded Character Set (UCS) - + Architecture and Basic Multilingual Plane, ISO/IEC 10646-1: + 1993". + + [6] "ITU-T Rec. X.690 (07/2002) | ISO/IEC 8825-1:2002, "Information + technology - ASN.1 encoding rules: Specification of Basic + Encoding Rules (BER), Canonical Encoding Rules (CER) and + Distinguished Encoding Rules (DER)", 2002.". + + [7] Rigney, C., "Remote Authentication Dial In User Service + (RADIUS)", RFC 2865, June 2000. + + [8] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [9] Aboba, B., "RADIUS and IPv6", RFC 3162, August 2001. + + [10] Melnikov, A., "Simple Authentication and Security Layer + (SASL)", RFC 4422, June 2006. + +7.2. Informative References + + [11] Weltman, R., "Lightweight Directory Access Protocol (LDAP) + Proxied Authorization Control", RFC 4370, February 2006. + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 17] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +Appendix A. Copyright + + Copyright (C) The IETF Trust (2007). This document is subject to the + rights, licenses and restrictions contained in BCP 78, and except as + set forth therein, the authors retain all their rights. This + document and the information contained herein are provided on an "AS + IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR + IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 18] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +Author's Address + + Mark Wahl + Informed Control Inc. + PO Box 90626 + Austin, TX 78709 + US + + Email: mark.wahl@informed-control.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wahl Expires November 10, 2007 [Page 19] + +Internet-Draft LDAP Session Tracking Control May 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + +Acknowledgment + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + +Wahl Expires November 10, 2007 [Page 20] + diff --git a/doc/drafts/draft-zeilenga-ldap-dontusecopy-xx.txt b/doc/drafts/draft-zeilenga-ldap-dontusecopy-xx.txt index 84065c8dfc..3341290cdd 100644 --- a/doc/drafts/draft-zeilenga-ldap-dontusecopy-xx.txt +++ b/doc/drafts/draft-zeilenga-ldap-dontusecopy-xx.txt @@ -5,13 +5,13 @@ INTERNET-DRAFT Kurt D. Zeilenga -Intended Category: Standard Track OpenLDAP Foundation -Expires in six months 5 March 2006 +Intended Category: Standard Track Isode Limited +Expires in six months 14 February 2007 The LDAP Don't Use Copy Control - + Status of this Memo @@ -21,7 +21,7 @@ Status of this Memo document. Distribution of this memo is unlimited. Technical discussion of this document will take place on the IETF LDAP Extensions mailing list . Please send editorial - comments directly to the author . + comments directly to the author . By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have @@ -38,13 +38,13 @@ Status of this Memo or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at - http://www.ietf.org/1id-abstracts.html + http://www.ietf.org/1id-abstracts.html. The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html + http://www.ietf.org/shadow.html. - Copyright (C) The Internet Society (2006). All Rights Reserved. + Copyright (C) The IETF Trust (2007). All Rights Reserved. Please see the Full Copyright section near the end of this document for more information. @@ -57,7 +57,7 @@ Status of this Memo Zeilenga LDAP Don't Use Copy Control [Page 1] -INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-04 14 February 2007 Abstract @@ -71,7 +71,7 @@ Abstract 1. Background and Intended Usage This document defines the Lightweight Directory Access Protocol (LDAP) - [Roadmap] Don't Use Copy control extension. The control may be + [RFC4510] Don't Use Copy control extension. The control may be attached to request messages to indicate that copied (replicated or cached) information [X.500] should not be used in providing service. This control is based upon the X.511 [X.511] dontUseCopy service @@ -94,14 +94,14 @@ Abstract 3. The Don't Use Copy Control - The Don't Use Copy control is an LDAP Control [Protocol] whose + The Don't Use Copy control is an LDAP Control [RFC4511] whose controlType is IANA-ASSIGNED-OID and controlValue is absent. The criticality MUST be TRUE. There is no corresponding response control. The control is appropriate for both LDAP interrogation operations, - including Compare and Search operations [Protocol]. It is + including Compare and Search operations [RFC4511]. It is inappropriate for all other operations, including Abandon, Bind, - Delete, Modify, ModifyDN, StartTLS, and Unbind operations [Protocol]. + Delete, Modify, ModifyDN, StartTLS, and Unbind operations [RFC4511]. When the control is attached to an LDAP request, the requested operation MUST NOT be performed on copied information. That is, the @@ -113,7 +113,7 @@ Abstract Zeilenga LDAP Don't Use Copy Control [Page 2] -INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-04 14 February 2007 is not available (either locally or through chaining), the server MUST @@ -121,6 +121,12 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 be better able to service the request or return an appropriate result code (e.g., unwillingToPerform). + Servers implementing this technical specification SHOULD publish the + object identifier IANA-ASSIGNED-OID as a value of the + 'supportedControl' attribute [RFC4512] in their root DSE. A server + MAY choose to advertise this extension only when the client is + authorized to use it. + 4. Security Considerations @@ -131,9 +137,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 consider whether use of copied information, in particular security and policy information, may result insecure behavior. - Security considerations for the base operations [Protocol] extended by + Security considerations for the base operations [RFC4511] extended by this control, as well as general LDAP security considerations - [Roadmap], generally apply to implementation and use of this + [RFC4510], generally apply to implementation and use of this extension. @@ -142,12 +148,12 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 5.1. Object Identifier It is requested that IANA assign upon Standards Action an LDAP Object - Identifier [BCP64bis] to identify the LDAP Don't Use Copy Control + Identifier [RFC4520] to identify the LDAP Don't Use Copy Control defined in this document. Subject: Request for LDAP Object Identifier Registration Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Specification: RFC XXXX Author/Change Controller: IESG Comments: @@ -155,23 +161,23 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 5.2 LDAP Protocol Mechanism - Registration of this protocol mechanism [BCP64bis] is requested. + Registration of this protocol mechanism [RFC4520] is requested. Subject: Request for LDAP Protocol Mechanism Registration - Object Identifier: IANA-ASSIGNED-OID - Description: Don't Use Copy Control - Person & email address to contact for further information: - Kurt Zeilenga - Usage: Control - Specification: RFC XXXX Zeilenga LDAP Don't Use Copy Control [Page 3] -INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-04 14 February 2007 + Object Identifier: IANA-ASSIGNED-OID + Description: Don't Use Copy Control + Person & email address to contact for further information: + Kurt Zeilenga + Usage: Control + Specification: RFC XXXX Author/Change Controller: IESG Comments: none @@ -180,9 +186,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 6. Author's Address Kurt D. Zeilenga - OpenLDAP Foundation + Isode Limited - Email: Kurt@OpenLDAP.org + Email: Kurt.Zeilenga@Isode.COM 7. References @@ -197,12 +203,14 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14 (also RFC 2119), March 1997. - [Roadmap] Zeilenga, K. (editor), "LDAP: Technical Specification - Road Map", draft-ietf-ldapbis-roadmap-xx.txt, a work in - progress. + [RFC4510] Zeilenga, K. (editor), "LDAP: Technical Specification + Road Map", RFC 4510, June 2006. + + [RFC4511] Sermersheim, J. (editor), "LDAP: The Protocol", RFC + 4511, June 2006. - [Protocol] Sermersheim, J. (editor), "LDAP: The Protocol", - draft-ietf-ldapbis-protocol-xx.txt, a work in progress. + [RFC4512] Zeilenga, K. (editor), "LDAP: Directory Information + Models", RFC 4512, June 2006. 7.2. Informative References @@ -212,23 +220,26 @@ INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 -- Overview of concepts, models and services," X.500(1993) (also ISO/IEC 9594-1:1994). + + + +Zeilenga LDAP Don't Use Copy Control [Page 4] + +INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-04 14 February 2007 + + [X.511] International Telecommunication Union - Telecommunication Standardization Sector, "The Directory: Abstract Service Definition", X.511(1993) (also ISO/IEC 9594-3:1993). - [BCP64bis] Zeilenga, K., "IANA Considerations for LDAP", - draft-ietf-ldapbis-bcp64-xx.txt, a work in progress. - - + [RFC4520] Zeilenga, K., "Internet Assigned Numbers Authority + (IANA) Considerations for the Lightweight Directory + Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006. -Zeilenga LDAP Don't Use Copy Control [Page 4] - -INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-02 5 March 2006 - -Intellectual Property Rights +Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to @@ -256,7 +267,7 @@ Intellectual Property Rights Full Copyright - Copyright (C) The Internet Society (2006). + Copyright (C) The IETF Trust (2007). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors @@ -264,10 +275,18 @@ Full Copyright This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + + + +Zeilenga LDAP Don't Use Copy Control [Page 5] + +INTERNET-DRAFT draft-zeilenga-ldap-dontusecopy-04 14 February 2007 + + + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. @@ -279,5 +298,42 @@ Full Copyright -Zeilenga LDAP Don't Use Copy Control [Page 5] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Zeilenga LDAP Don't Use Copy Control [Page 6] diff --git a/doc/drafts/draft-zeilenga-ldap-noop-xx.txt b/doc/drafts/draft-zeilenga-ldap-noop-xx.txt index 100a845bb6..9411c386a1 100644 --- a/doc/drafts/draft-zeilenga-ldap-noop-xx.txt +++ b/doc/drafts/draft-zeilenga-ldap-noop-xx.txt @@ -5,13 +5,13 @@ INTERNET-DRAFT Kurt D. Zeilenga -Intended Category: Standard Track OpenLDAP Foundation -Expires in six months 5 March 2006 +Intended Category: Standard Track Isode Limited +Expires in six months 14 February 2007 The LDAP No-Op Control - + Status of this Memo @@ -21,7 +21,7 @@ Status of this Memo document. Distribution of this memo is unlimited. Technical discussion of this document will take place on the IETF LDAP Extensions mailing list . Please send editorial - comments directly to the author . + comments directly to the author . By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have @@ -38,13 +38,13 @@ Status of this Memo or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at - http://www.ietf.org/1id-abstracts.html + http://www.ietf.org/1id-abstracts.html. The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html + http://www.ietf.org/shadow.html. - Copyright (C) The Internet Society (2006). All Rights Reserved. + Copyright (C) The IETF Trust (2007). All Rights Reserved. Please see the Full Copyright section near the end of this document for more information. @@ -57,7 +57,7 @@ Status of this Memo Zeilenga LDAP No-Op Control [Page 1] -INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-noop-10 14 February 2007 Abstract @@ -71,7 +71,7 @@ Abstract 1. Overview It is often desirable to be able to determine if a directory operation - [Protocol] would successful complete or not without having the normal + [RFC4511] would successful complete or not without having the normal effect of the operation take place. For example, an administrative client might want to verify that new user could update their entry (and not other entries) without the directory actually being updated. @@ -79,7 +79,7 @@ Abstract auditing tools. This document defines the Lightweight Directory Access Protocol (LDAP) - [Roadmap] No-Op control extension. The presence of the No-Op control + [RFC4510] No-Op control extension. The presence of the No-Op control in an operation request message disables its normal effect upon the directory which operation would otherwise have. Instead of updating the directory and returning the normal indication of success, the @@ -87,7 +87,7 @@ Abstract noOperation resultCode (introduced below). For example, when the No-Op control is present in a LDAP modify - operation [Protocol], the server is do all processing necessary to + operation [RFC4511], the server is do all processing necessary to perform the operation without actually updating the directory. If it detects an error during this processing, it returns a non-success (other than noOperation) resultCode as it normally would. Otherwise, @@ -113,18 +113,18 @@ Abstract Zeilenga LDAP No-Op Control [Page 2] -INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-noop-10 14 February 2007 2. No-Op Control - The No-Op control is an LDAP Control [Protocol] whose controlType is + The No-Op control is an LDAP Control [RFC4511] whose controlType is IANA-ASSIGNED-OID and controlValue is absent. Clients MUST provide a criticality value of TRUE to prevent unintended modification of the directory. The control is appropriate for request messages of LDAP Add, Delete, - Modify and ModifyDN operations [Protocol]. The control is also + Modify and ModifyDN operations [RFC4511]. The control is also appropriate for requests of extended operations which update the directory (or other data stores), such as Password Modify Extended Operation [RFC3062]. There is no corresponding response control. @@ -145,7 +145,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 Servers SHOULD indicate their support for this control by providing IANA-ASSIGNED-OID as a value of the 'supportedControl' attribute type - [Models] in their root DSE entry. A server MAY choose to advertise + [RFC4512] in their root DSE entry. A server MAY choose to advertise this extension only when the client is authorized to use this operation. @@ -159,8 +159,8 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 tools. Implementors of this LDAP extension should be familiar with security - considerations applicable to the LDAP operations [Protocol] extended - by this control, as well as general LDAP security considerations + considerations applicable to the LDAP operations [RFC4511] extended by + this control, as well as general LDAP security considerations [Roadmap]. @@ -169,19 +169,19 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 Zeilenga LDAP No-Op Control [Page 3] -INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-noop-10 14 February 2007 4. IANA Considerations 4.1. Object Identifier - It is requested that IANA assign an LDAP Object Identifier [BCP64bis] + It is requested that IANA assign an LDAP Object Identifier [RFC4520] to identify the LDAP No-Op Control defined in this document. Subject: Request for LDAP Object Identifier Registration Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Specification: RFC XXXX Author/Change Controller: IESG Comments: @@ -190,13 +190,13 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 4.2 LDAP Protocol Mechanism - Registration of this protocol mechanism is requested [RFC3383]. + Registration of this protocol mechanism is requested [RFC4520]. Subject: Request for LDAP Protocol Mechanism Registration Object Identifier: IANA-ASSIGNED-OID Description: No-Op Control Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Usage: Control Specification: RFC XXXX Author/Change Controller: IESG @@ -209,7 +209,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 Subject: LDAP Result Code Registration Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Result Code Name: noOperation Specification: RFC XXXX Author/Change Controller: IESG @@ -219,16 +219,16 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 5. Author's Address Kurt D. Zeilenga - OpenLDAP Foundation + Isode Limited Zeilenga LDAP No-Op Control [Page 4] -INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-noop-10 14 February 2007 - Email: Kurt@OpenLDAP.org + Email: Kurt.Zeilenga@Isode.COM 6. References @@ -243,16 +243,14 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14 (also RFC 2119), March 1997. - [Protocol] Sermersheim, J. (editor), "LDAP: The Protocol", - draft-ietf-ldapbis-protocol-xx.txt, a work in progress. + [RFC4510] Zeilenga, K. (editor), "LDAP: Technical Specification + Road Map", RFC 4510, June 2006. - [Roadmap] Zeilenga, K. (editor), "LDAP: Technical Specification - Road Map", draft-ietf-ldapbis-roadmap-xx.txt, a work in - progress. + [RFC4511] Sermersheim, J. (editor), "LDAP: The Protocol", RFC + 4511, June 2006. - [Models] Zeilenga, K. (editor), "LDAP: Directory Information - Models", draft-ietf-ldapbis-models-xx.txt, a work in - progress. + [RFC4512] Zeilenga, K. (editor), "LDAP: Directory Information + Models", RFC 4512, June 2006. 6.2. Informative References @@ -268,23 +266,24 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 [RFC3062] Zeilenga, K., "LDAP Password Modify Extended Operation", RFC 3062, February 2000. - [BCP64bis] Zeilenga, K., "IANA Considerations for LDAP", - draft-ietf-ldapbis-bcp64-xx.txt, a work in progress. + [RFC4520] Zeilenga, K., "Internet Assigned Numbers Authority + (IANA) Considerations for the Lightweight Directory + Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006. -Intellectual Property Rights +Intellectual Property The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to Zeilenga LDAP No-Op Control [Page 5] -INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 +INTERNET-DRAFT draft-zeilenga-ldap-noop-10 14 February 2007 - Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has @@ -309,7 +308,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-noop-08 5 March 2006 Full Copyright - Copyright (C) The Internet Society (2006). + Copyright (C) The IETF Trust (2007). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors @@ -317,10 +316,10 @@ Full Copyright This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. @@ -335,5 +334,6 @@ Full Copyright + Zeilenga LDAP No-Op Control [Page 6] diff --git a/doc/drafts/draft-zeilenga-ldap-managedit-xx.txt b/doc/drafts/draft-zeilenga-ldap-relax.txt similarity index 64% rename from doc/drafts/draft-zeilenga-ldap-managedit-xx.txt rename to doc/drafts/draft-zeilenga-ldap-relax.txt index f73f2a3ff4..c656f9ed89 100644 --- a/doc/drafts/draft-zeilenga-ldap-managedit-xx.txt +++ b/doc/drafts/draft-zeilenga-ldap-relax.txt @@ -5,13 +5,13 @@ INTERNET-DRAFT Kurt D. Zeilenga -Intended Category: Experimental OpenLDAP Foundation -Expires in six months 27 February 2006 +Intended Category: Experimental Isode Limited +Expires in six months 14 February 2007 - The LDAP Manage Directory Information Tree Control - + The LDAP Relax Rules Control + Status of this Memo @@ -21,7 +21,9 @@ Status of this Memo Experimental document. Distribution of this memo is unlimited. Technical discussion of this document will take place on the IETF LDAP Extensions mailing list . Please send editorial - comments directly to the author . + comments directly to the author . + + This document replaces draft-zeilenga-ldap-managedit-xx.txt. By submitting this Internet-Draft, each author represents that any applicable patent or other IPR claims of which he or she is aware have @@ -38,13 +40,13 @@ Status of this Memo or to cite them other than as "work in progress." The list of current Internet-Drafts can be accessed at - http://www.ietf.org/1id-abstracts.html + http://www.ietf.org/1id-abstracts.html. The list of Internet-Draft Shadow Directories can be accessed at - http://www.ietf.org/shadow.html + http://www.ietf.org/shadow.html. - Copyright (C) The Internet Society (2006). All Rights Reserved. + Copyright (C) The IETF Trust (2007). All Rights Reserved. Please see the Full Copyright section near the end of this document for more information. @@ -53,30 +55,28 @@ Status of this Memo - - -Zeilenga LDAP Manage DIT Control [Page 1] +Zeilenga LDAP Relax Rules Control [Page 1] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 Abstract This document defines the Lightweight Directory Access Protocol (LDAP) - Manage Directory Information Tree (DIT) Control which allows a - directory user agent (a client) to request the directory service - temporarily relax enforcement of constraints of the X.500 models. + Relax Rules Control which allows a directory user agent (a client) to + request the directory service temporarily relax enforcement of various + data and service model rules. 1. Background and Intended Use Directory servers accessible via Lightweight Directory Access Protocol - (LDAP) [Roadmap] are expected to act in accordance with the X.500 - series of ITU-T Recommendations. In particular, servers are expected - to ensure the X.500 data and service models are not violated. + (LDAP) [RFC4510] are expected to act in accordance with the X.500 + [X.500] series of ITU-T Recommendations. In particular, servers are + expected to ensure the X.500 data and service models are not violated. An LDAP server is expected to prevent modification of the structural - object class of an object [Models]. That is, the X.500 models do not + object class of an object [RFC4512]. That is, the X.500 models do not allow a 'person' object to be transformed into an 'organizationalPerson' object through modification of the object. Instead, the 'person' object must be deleted and then a new @@ -86,34 +86,34 @@ Abstract two operations in a single transaction, the intermediate directory state (after the delete, before the add) is visible to other clients, which may lead to undesirable client behavior. Second, attributes - such as entryUUID [entryUUID] will reflect the object was replaced, + such as 'entryUUID' [RFC4530] will reflect the object was replaced, not transformed. An LDAP server is expected to prevent clients from modifying values of - NO-USER-MODIFICATION attributes [Models]. For instance, an entry is - not allowed to assign or modify the value of the entryUUID attribute. - However, where an administrator is restoring a previously existing - object, for instance when repartitioning data between directory - servers or when migrating from one vendor server product to another, - it may be desirable to allow the client to assign or modify the value - of the entryUUID attribute. - - This document specifies the Manage Directory Information Tree (DIT) - control. The Manage DIT control may be attached to LDAP requests to - update the DIT to request DIT restrictions be temporarily relaxed + NO-USER-MODIFICATION attributes [RFC4512]. For instance, an entry is + not allowed to assign or modify the value of the 'entryUUID' + attribute. However, where an administrator is restoring a previously + existing object, for instance when repartitioning data between + directory servers or when migrating from one vendor server product to + another, it may be desirable to allow the client to assign or modify + the value of the 'entryUUID' attribute. + + This document defines the LDAP Relax Rules control. This control may + be attached to LDAP requests to update the Directory Information Tree + (DIT) to request various data and service rules be temporarily relaxed during the performance of the requested DIT update. The server is however to ensure the resulting directory state is valid. Use of this control is expected that use of this extension will be restricted by administrative and/or access controls. It is intended - to be used by directory administrators. + to be used primarily by directory administrators. -Zeilenga LDAP Manage DIT Control [Page 2] +Zeilenga LDAP Relax Rules Control [Page 2] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 This extension is considered experimental as it is not yet clear @@ -128,28 +128,28 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 Protocol elements are described using ASN.1 [X.680] with implicit tags. The term "BER-encoded" means the element is to be encoded using the Basic Encoding Rules [X.690] under the restrictions detailed in - Section 5.2 of [Protocol]. + Section 5.1 of [RFC4511]. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119]. - DSA stands for Directory System Agent, a server. DSE stands for DSA- - specific Entry. + DSA stands for Directory System Agent, a server. DSE stands for + DSA-specific Entry. -2. The Manage DIT Control +2. The Relax Rules Control - The Manage DIT control is an LDAP Control [Protocol] whose controlType + The Relax Rules control is an LDAP Control [RFC4511] whose controlType is IANA-ASSIGNED-OID, controlValue is empty, and the criticality of TRUE. There is no corresponding response control. The control is appropriate for all LDAP update requests, including - add, delete, modify, and modifyDN (rename) [Protocol]. + add, delete, modify, and modifyDN (rename) [RFC4511]. - The presence of the Manage DIT control in an LDAP update request + The presence of the Rules Rules control in an LDAP update request indicates the server temporarily relax X.500 model contraints during performance of the directory update. @@ -167,9 +167,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 -Zeilenga LDAP Manage DIT Control [Page 3] +Zeilenga LDAP Relax Rules Control [Page 3] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 DIT content rule may contain an attribute now precluded by the current @@ -177,9 +177,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 Servers implementing this technical specification SHOULD publish the object identifier IANA-ASSIGNED-OID as a value of the - 'supportedControl' attribute [Models] in their root DSE. A server MAY - choose to advertise this extension only when the client is authorized - to use it. + 'supportedControl' attribute [RFC4512] in their root DSE. A server + MAY choose to advertise this extension only when the client is + authorized to use it. 3. Use Cases @@ -189,9 +189,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 In absence of this control, an attempt to modify an object's 'objectClass' in a manner which cause a change in the structural object class of the object would normally lead to an - objectClassModsProhibited error [Protocol]. The presence of the - Manage DIT control in the modify request requests the change be - allowed. If the server is willing and able to allow the change in the + objectClassModsProhibited error [RFC4511]. The presence of the Relax + Rules control in the modify request requests the change be allowed. + If the server is willing and able to allow the change in the structural object class of the object. For instance, to change an 'organization' object into an @@ -215,20 +215,20 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.2. Inactive Attribute Types - In absence of the Manage DIT control, an attempt to add or modify + In absence of the Relax Rules control, an attempt to add or modify values to an attribute whose type has been marked inactive in the controlling subschema (its attribute type description contains the - OBSOLETE field) [Models] normally results in a failure. + OBSOLETE field) [RFC4512] normally results in a failure. -Zeilenga LDAP Manage DIT Control [Page 4] +Zeilenga LDAP Relax Rules Control [Page 4] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 - In the presence of the Manage DIT control, the server performs the + In the presence of the Relax Rules control, the server performs the update operation as if the attribute's type is marked active in the controlling subschema (its attribute type description does not contain the OBSOLETE field). @@ -236,13 +236,14 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.3. DIT Content Rules - In absence of the Manage DIT control, an attempt to include the name + In absence of the Relax Rules control, an attempt to include the name (or OID) of an auxiliary class to an object's 'objectClass' which is not allowed by the controlling DIT Content Rule would be disallowed - [Models]. Additionally, an attempt to add values of an attribute not - allowed (or explicitly precluded) by the DIT Content Rule would fail. + [RFC4512]. Additionally, an attempt to add values of an attribute + not allowed (or explicitly precluded) by the DIT Content Rule would + fail. - In presence of the Manage DIT control, the server performs the update + In presence of the Relax Rules control, the server performs the update operation as if the controlling DIT Content Rule allowed any and all known auxiliary classses to be present and allowed any and all known attributes to be present (and precluded no attributes). @@ -250,11 +251,11 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.4. DIT Structure Rules and Name Forms - In absence of the Manage DIT control, the service enforces DIT + In absence of the Relax Rules control, the service enforces DIT structure rules and name form requirements of the controlling - subschema [Models]. + subschema [RFC4512]. - In the presence of the Manage DIT control, the server performs the + In the presence of the Relax Rules control, the server performs the update operation ignoring all DIT structure rules and name forms in the controlling subschema. @@ -274,17 +275,17 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.6. NO-USER-MODIFICATION attribute modification In absence of this control, an attempt to modify values of a - NO-USER-MODIFICATION attribute would normally lead to a - constraintViolation or other appropriate error [Protocol]. In the + NO-USER-MODIFICATION attribute [RFC4512] would normally lead to a -Zeilenga LDAP Manage DIT Control [Page 5] +Zeilenga LDAP Relax Rules Control [Page 5] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 - presence of the Manage DIT control in the update request requests the + constraintViolation or other appropriate error [RFC4511]. In the + presence of the Relax Rules control in the update request requests the modification be allowed. Relaxation of the NO-USER-MODIFICATION constraint is not appropriate @@ -295,7 +296,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 change in the structuralObjectClass class, values of objectClass should be changed as discussed in Section 3.1. Other attributes for which the NO-USER-MODIFICATION constraint should not be relaxed - include 'entryDN' [EntryDN], 'subschemaSubentry' [Models], and + include 'subschemaSubentry' [RFC4512] and 'collectiveAttributeSubentries' [RFC3671]. The subsections of this section discuss modification of various @@ -308,11 +309,11 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 attribute. -3.1.1. entryUUID +3.1.1. 'entryUUID' attribute - To provide a value for the 'entryUUID' attribute on entry creation, - the client should issue an LDAP Add request with a Manage DIT control - providing the desired value. For instance: + To provide a value for the 'entryUUID' [RFC4530] attribute on entry + creation, the client should issue an LDAP Add request with a Relax + Rules control providing the desired value. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID @@ -326,20 +327,20 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 To provide a replacement value for the 'entryUUID' after entry creation, the client should issue an LDAP Modify request with a - Manage DIT control including an approrpiate change. For instance: + Relax Rules control including an approrpiate change. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID changetype: modify - replace: entryUUID -Zeilenga LDAP Manage DIT Control [Page 6] +Zeilenga LDAP Relax Rules Control [Page 6] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 + replace: entryUUID entryUUID: 597ae2f6-16a6-1027-98f4-d28b5365dc14 - @@ -349,10 +350,10 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.2.2. createTimestamp - To provide a value for the 'createTimestamp' attribute on entry - creation, the client should issue an LDAP Add request with a Manage - DIT control providing the desired 'createTimestamp' value. For - instance: + To provide a value for the 'createTimestamp' [RFC4512] attribute + on entry creation, the client should issue an LDAP Add request with + a Relax Rules control providing the desired 'createTimestamp' + value. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID @@ -366,7 +367,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 To provide a replacement value for the 'createTimestamp' after entry creation, the client should issue an LDAP Modify request with - a Manage DIT control including an approrpiate change. For instance: + a Relax Rules control including an approrpiate change. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID @@ -386,18 +387,18 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.2.3. modifyTimestamp - To provide a value for the 'modifyTimestamp' attribute on entry - creation, the client should issue an LDAP Add request with a Manage + To provide a value for the 'modifyTimestamp' [RFC4512] attribute -Zeilenga LDAP Manage DIT Control [Page 7] +Zeilenga LDAP Relax Rules Control [Page 7] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 - DIT control providing the desired 'modifyTimestamp' value. For - instance: + on entry creation, the client should issue an LDAP Add request with + a Relax Rules control providing the desired 'modifyTimestamp' + value. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID @@ -411,7 +412,7 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 To provide a replacement value for the 'modifyTimestamp' after entry creation, the client should issue an LDAP Modify - request with a Manage DIT control including an approrpiate + request with a Relax Rules control including an approrpiate change. For instance: dn: ou=Unit,dc=example,dc=net @@ -433,9 +434,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 3.2.3. creatorsName and modifiersName To provide a value for the 'creatorsName' and/or 'modifiersName' - attribute on entry creation, the client should issue an LDAP Add - request with a Manage DIT control providing the desired values. - For instance: + [RFC4512] attribute on entry creation, the client should issue an + LDAP Add request with a Relax Rules control providing the desired + values. For instance: dn: ou=Unit,dc=example,dc=net control: IANA-ASSIGNED-OID @@ -443,21 +444,22 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 objectClass: organizationalUnit ou: Unit creatorsName: cn=Jane Doe,dc=example,net - modifiersName: cn=Jane Doe,dc=example,net -Zeilenga LDAP Manage DIT Control [Page 8] +Zeilenga LDAP Relax Rules Control [Page 8] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 + + modifiersName: cn=Jane Doe,dc=example,net In this case, the server is either to add the entry using the provided values or fail the request. To provide a replacement values after entry creation for either of the 'creatorsName' or 'modifiersName' attributes or both, the - client should issue an LDAP Modify request with a Manage DIT control + client should issue an LDAP Modify request with a Relax Rules control including the approrpiate changes. For instance: dn: ou=Unit,dc=example,dc=net @@ -480,9 +482,9 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 and access controls. Use of this mechanism is intended to be restricted to directory administrators. - Security considerations for the base operations [Protocol] extended + Security considerations for the base operations [RFC4511] extended by this control, as well as general LDAP security considerations - [Roadmap], generally apply to implementation and use of this + [RFC4510], generally apply to implementation and use of this extension. @@ -490,45 +492,46 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 5.1. Object Identifier - It is requested that IANA assign a LDAP Object Identifier [BCP64bis] - to identify the LDAP Assertion Control defined in this document. + It is requested that the IANA assign a LDAP Object Identifier + [RFC4520] to identify the LDAP Relax Rules Control defined in this + document. Subject: Request for LDAP Object Identifier Registration Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Specification: RFC XXXX - Author/Change Controller: Kurt Zeilenga - Comments: Identifies the LDAP Manage DIT Control - -Zeilenga LDAP Manage DIT Control [Page 9] +Zeilenga LDAP Relax Rules Control [Page 9] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 + Author/Change Controller: Kurt Zeilenga + Comments: Identifies the LDAP Relax Rules Control + 5.2 LDAP Protocol Mechanism - Registration of this protocol mechanism [BCP64bis] is requested. + Registration of this protocol mechanism [RFC4520] is requested. Subject: Request for LDAP Protocol Mechanism Registration Object Identifier: IANA-ASSIGNED-OID - Description: Manage DIT Control + Description: Relax Rules Control Person & email address to contact for further information: - Kurt Zeilenga + Kurt Zeilenga Usage: Control Specification: RFC XXXX - Author/Change Controller: Kurt Zeilenga + Author/Change Controller: Kurt Zeilenga Comments: none 6. Author's Address Kurt D. Zeilenga - OpenLDAP Foundation + Isode Limited - Email: Kurt@OpenLDAP.org + Email: Kurt.Zeilenga@Isode.COM 7. References @@ -543,39 +546,45 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14 (also RFC 2119), March 1997. - [Roadmap] Zeilenga, K. (editor), "LDAP: Technical Specification - Road Map", draft-ietf-ldapbis-roadmap-xx.txt, a work in - progress. + [RFC3671] Zeilenga, K., "Collective Attributes in LDAP", RFC 3671, + December 2003. - [Models] Zeilenga, K. (editor), "LDAP: Directory Information - Models", draft-ietf-ldapbis-models-xx.txt, a work in - progress. + [RFC4510] Zeilenga, K. (editor), "LDAP: Technical Specification + Road Map", RFC 4510, June 2006. + [RFC4511] Sermersheim, J. (editor), "LDAP: The Protocol", RFC + 4511, June 2006. + [RFC4512] Zeilenga, K. (editor), "LDAP: Directory Information -7.2. Informative References - [BCP64bis] Zeilenga, K., "IANA Considerations for LDAP", +Zeilenga LDAP Relax Rules Control [Page 10] + +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 -Zeilenga LDAP Manage DIT Control [Page 10] - -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 + Models", RFC 4512, June 2006. + [RFC4530] Zeilenga, K., "Lightweight Directory Access Protocol + (LDAP) entryUUID Operational Attribute", RFC 4530, June + 2006. - draft-ietf-ldapbis-bcp64-xx.txt, a work in progress. + [X.500] International Telecommunication Union - + Telecommunication Standardization Sector, "The Directory + -- Overview of concepts, models and services," + X.500(1993) (also ISO/IEC 9594-1:1994). - [EntryUUID] Zeilenga, K., "The LDAP EntryUUID Operational - Attribute", draft-zeilenga-ldap-uuid-xx.txt, a work in - progress. - [RFC2849] Good, G., "The LDAP Data Interchange Format (LDIF) - - Technical Specification", RFC 2849, June 2000. +7.2. Informative References + [RFC4520] Zeilenga, K., "Internet Assigned Numbers Authority + (IANA) Considerations for the Lightweight Directory + Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006. -Intellectual Property Rights + +Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to @@ -603,36 +612,27 @@ Intellectual Property Rights Full Copyright - Copyright (C) The Internet Society (2006). - - This document is subject to the rights, licenses and restrictions - contained in BCP 78, and except as set forth therein, the authors - retain all their rights. - - This document and the information contained herein are provided on an - "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS - OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET -Zeilenga LDAP Manage DIT Control [Page 11] +Zeilenga LDAP Relax Rules Control [Page 11] -INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 - - - ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - - - - +INTERNET-DRAFT draft-zeilenga-ldap-relax-01 14 February 2007 + Copyright (C) The IETF Trust (2007). + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. @@ -671,5 +671,5 @@ INTERNET-DRAFT draft-zeilenga-ldap-managedit-00 27 February 2006 -Zeilenga LDAP Manage DIT Control [Page 12] +Zeilenga LDAP Relax Rules Control [Page 12] diff --git a/doc/man/man1/ldapcompare.1 b/doc/man/man1/ldapcompare.1 index ea5d7c20ae..4adffa6ed8 100644 --- a/doc/man/man1/ldapcompare.1 +++ b/doc/man/man1/ldapcompare.1 @@ -108,6 +108,18 @@ Use \fIpasswd\fP as the password for simple authentication. .BI \-y \ passwdfile Use complete contents of \fIpasswdfile\fP as the password for simple authentication. +Note that \fIcomplete\fP means that any leading or trailing whitespaces, +including newlines, will be considered part of the password and, +unlike other software, they will not be stripped. +As a consequence, passwords stored in files by commands like +.BR echo (1) +will not behave as expected, since +.BR echo (1) +by default appends a trailing newline to the echoed string. +The recommended portable way to store a cleartext password in a file +for use with this option is to use +.BR slappasswd (8) +with \fI{CLEARTEXT}\fP as hash and the option \fI\-n\fP. .TP .BI \-H \ ldapuri Specify URI(s) referring to the ldap server(s); only the protocol/host/port diff --git a/doc/man/man1/ldapmodrdn.1 b/doc/man/man1/ldapmodrdn.1 index 5d58bd7032..b82ed1d7e7 100644 --- a/doc/man/man1/ldapmodrdn.1 +++ b/doc/man/man1/ldapmodrdn.1 @@ -9,6 +9,8 @@ ldapmodrdn \- LDAP rename entry tool [\c .BR \-r ] [\c +.BI \-s \ newsup\fR] +[\c .BR \-n ] [\c .BR \-v ] @@ -74,6 +76,10 @@ option, or from the command-line pair \fIdn\fP and .B \-r Remove old RDN values from the entry. Default is to keep old values. .TP +.BI \-s \ newsup +Specify a new superior entry. (I.e., move the target entry and make it a +child of the new superior.) This option is not supported in LDAPv2. +.TP .B \-n Show what would be done, but don't actually change entries. Useful for debugging in conjunction with -v. diff --git a/doc/man/man1/ldapsearch.1 b/doc/man/man1/ldapsearch.1 index 1350f9074a..2e798111a4 100644 --- a/doc/man/man1/ldapsearch.1 +++ b/doc/man/man1/ldapsearch.1 @@ -173,7 +173,7 @@ must be compiled with LDAP_DEBUG defined for this option to have any effect. Read a series of lines from \fIfile\fP, performing one LDAP search for each line. In this case, the \fIfilter\fP given on the command line is treated as a pattern where the first and only occurrence of \fB%s\fP -is replaced with a line from \fIfile\fP. Any other occurence of the +is replaced with a line from \fIfile\fP. Any other occurrence of the the \fB%\fP character in the pattern will be regarded as an error. Where it is desired that the search filter include a \fB%\fP character, the character should be encoded as \fB\\25\fP (see RFC 4515). @@ -201,9 +201,14 @@ Use complete contents of \fIpasswdfile\fP as the password for simple authentication. .TP .BI \-H \ ldapuri -Specify URI(s) referring to the ldap server(s); only the protocol/host/port -fields are allowed; a list of URI, separated by whitespace or commas -is expected. +Specify URI(s) referring to the ldap server(s); +a list of URI, separated by whitespace or commas is expected; +only the protocol/host/port fields are allowed. +As an exception, if no host/port is specified, but a DN is, +the DN is used to look up the corresponding host(s) using the +DNS SRV records, according to RFC 2782. The DN must be a non-empty +sequence of AVAs whose attribute type is "dc" (domain component), +and must be escaped according to RFC 2396. .TP .BI \-h \ ldaphost Specify an alternate host on which the ldap server is running. diff --git a/doc/man/man3/Deprecated b/doc/man/man3/Deprecated index 6d850c0368..3b7f6960ab 100644 --- a/doc/man/man3/Deprecated +++ b/doc/man/man3/Deprecated @@ -1,7 +1,7 @@ Deprecated interfaces generally remain in the library. The macro LDAP_DEPRECATED can be defined to a non-zero value (e.g., -DLDAP_DEPRECATED=1) when compiling program designed to use -deprecated interaces. It is recommended that developers writing new +deprecated interfaces. It is recommended that developers writing new programs, or updating old programs, avoid use of deprecated interfaces. Over time, it is expected that documentation (and, eventually, support) for deprecated interfaces to be eliminated. diff --git a/doc/man/man3/lber-decode.3 b/doc/man/man3/lber-decode.3 index f677f2df56..e2644c561c 100644 --- a/doc/man/man3/lber-decode.3 +++ b/doc/man/man3/lber-decode.3 @@ -3,11 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ber_get_next, ber_skip_tag, ber_peek_tag, ber_scanf, ber_get_int, -ber_get_enum, ber_get_stringb, ber_get_stringa, ber_get_stringal, -ber_get_stringbv, ber_get_null, ber_get_boolean, ber_get_bitstring, -ber_first_element, ber_next_element -\- LBER simplified Basic Encoding Rules library routines for decoding +ber_get_next, ber_skip_tag, ber_peek_tag, ber_scanf, ber_get_int, ber_get_enum, ber_get_stringb, ber_get_stringa, ber_get_stringal, ber_get_stringbv, ber_get_null, ber_get_boolean, ber_get_bitstring, ber_first_element, ber_next_element \- OpenLDAP LBER simplified Basic Encoding Rules library routines for decoding .SH LIBRARY OpenLDAP LBER (liblber, -llber) .SH SYNOPSIS diff --git a/doc/man/man3/lber-encode.3 b/doc/man/man3/lber-encode.3 index 275d42cb09..6d9a48da05 100644 --- a/doc/man/man3/lber-encode.3 +++ b/doc/man/man3/lber-encode.3 @@ -3,7 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ber_alloc_t, ber_flush, ber_flush2, ber_printf, ber_put_int, ber_put_enum, ber_put_ostring, ber_put_string, ber_put_null, ber_put_boolean, ber_put_bitstring, ber_start_seq, ber_start_set, ber_put_seq, ber_put_set \- LBER simplified Basic Encoding Rules library routines for encoding +ber_alloc_t, ber_flush, ber_flush2, ber_printf, ber_put_int, ber_put_enum, ber_put_ostring, ber_put_string, ber_put_null, ber_put_boolean, ber_put_bitstring, ber_start_seq, ber_start_set, ber_put_seq, ber_put_set \- OpenLDAP LBER simplified Basic Encoding Rules library routines for encoding .SH LIBRARY OpenLDAP LBER (liblber, -llber) .SH SYNOPSIS diff --git a/doc/man/man3/lber-memory.3 b/doc/man/man3/lber-memory.3 index 0a4e968d34..dfede5a21a 100644 --- a/doc/man/man3/lber-memory.3 +++ b/doc/man/man3/lber-memory.3 @@ -3,7 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree, ber_memvfree \- LBER memory allocators +ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree, ber_memvfree \- OpenLDAP LBER memory allocators .SH LIBRARY OpenLDAP LBER (liblber, -llber) .SH SYNOPSIS diff --git a/doc/man/man3/lber-sockbuf.3 b/doc/man/man3/lber-sockbuf.3 index d2e2b5364d..5ab9c1d848 100644 --- a/doc/man/man3/lber-sockbuf.3 +++ b/doc/man/man3/lber-sockbuf.3 @@ -3,8 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ber_sockbuf_alloc, ber_sockbuf_free, ber_sockbuf_ctrl, ber_sockbuf_add_io, -ber_sockbuf_remove_io, Sockbuf_IO \- LBER I/O infrastructure +ber_sockbuf_alloc, ber_sockbuf_free, ber_sockbuf_ctrl, ber_sockbuf_add_io, ber_sockbuf_remove_io, Sockbuf_IO \- OpenLDAP LBER I/O infrastructure .SH LIBRARY OpenLDAP LBER (liblber, -llber) .SH SYNOPSIS diff --git a/doc/man/man3/lber-types.3 b/doc/man/man3/lber-types.3 index 3ca443c6ca..a58c4f3cfe 100644 --- a/doc/man/man3/lber-types.3 +++ b/doc/man/man3/lber-types.3 @@ -3,12 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ber_int_t, ber_uint_t, ber_len_t, ber_slen_t, ber_tag_t, -struct berval, BerValue, BerVarray, BerElement, -ber_bvfree, ber_bvecfree, ber_bvecadd, ber_bvarray_free, ber_bvarray_add, -ber_bvdup, ber_dupbv, ber_bvstr, ber_bvstrdup, ber_str2bv, -ber_alloc_t, ber_init, ber_init2, ber_free -\- LBER types and allocation functions +ber_int_t, ber_uint_t, ber_len_t, ber_slen_t, ber_tag_t, struct berval, BerValue, BerVarray, BerElement, ber_bvfree, ber_bvecfree, ber_bvecadd, ber_bvarray_free, ber_bvarray_add, ber_bvdup, ber_dupbv, ber_bvstr, ber_bvstrdup, ber_str2bv, ber_alloc_t, ber_init, ber_init2, ber_free \- OpenLDAP LBER types and allocation functions .SH LIBRARY OpenLDAP LBER (liblber, -llber) .SH SYNOPSIS @@ -95,7 +90,7 @@ points to .B bv_len octets. .B bv_val -is not necessarily terminated by a NUL (zero) octet. +is not necessarily terminated by a NULL (zero) octet. .BR ber_bvfree () frees a BerValue, pointed to by \fIbv\fP, returned from this API. If \fIbv\fP is NULL, the routine does nothing. diff --git a/doc/man/man3/ldap.3 b/doc/man/man3/ldap.3 index 3dd34f7538..67d753937e 100644 --- a/doc/man/man3/ldap.3 +++ b/doc/man/man3/ldap.3 @@ -3,7 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap - OpenLDAP Lightweight Directory Access Protocol API +ldap \- OpenLDAP Lightweight Directory Access Protocol API .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS @@ -88,10 +88,14 @@ Search filters to be passed to the search routines are to be constructed by hand and should conform to RFC 4515 UTF\-8 string representation. .LP -LDAP URL are to be passed to routines are expected to conform +LDAP URLs to be passed to routines are expected to conform to RFC 4516 format. The .BR ldap_url (3) routines can be used to work with LDAP URLs. +.LP +LDAP controls to be passed to routines can be manipulated using the +.BR ldap_controls (3) +routines. .SH DISPLAYING RESULTS Results obtained from the search routines can be output by hand, by calling @@ -184,6 +188,12 @@ list of LDAP errors and their meanings .SM ldap_err2string(3) convert LDAP error indication to a string .TP +.SM ldap_extended_operation(3) +asynchronously perform an arbitrary extended operation +.TP +.SM ldap_extended_operation_s(3) +synchronously perform an arbitrary extended operation +.TP .SM ldap_first_attribute(3) return first attribute name in an entry .TP diff --git a/doc/man/man3/ldap_bind.3 b/doc/man/man3/ldap_bind.3 index 07c4129fbb..6b26f84311 100644 --- a/doc/man/man3/ldap_bind.3 +++ b/doc/man/man3/ldap_bind.3 @@ -265,7 +265,7 @@ The .B ldap_unbind_ext() and .B ldap_unbind_ext_s() -allows the operations to sepicify controls. +allows the operations to specify controls. .SH ERRORS Asynchronous routines will return -1 in case of error, setting the \fIld_errno\fP parameter of the \fIld\fP structure. Synchronous diff --git a/doc/man/man3/ldap_controls.3 b/doc/man/man3/ldap_controls.3 index 7cb7d21ddd..413ce0817e 100644 --- a/doc/man/man3/ldap_controls.3 +++ b/doc/man/man3/ldap_controls.3 @@ -3,45 +3,80 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_create_control, ldap_find_control, ldap_control_free, ldap_controls_free \- LDAP control manipulation routines +ldap_control_create, ldap_control_find, ldap_control_dup, +ldap_controls_dup, ldap_control_free, ldap_controls_free +\- LDAP control manipulation routines .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS .B #include .LP -.BI "int ldap_create_control(LDAP_CONST char *" OID ", BerElement *" ber ", int " iscritical ", LDAPControl **" ctrlp ");" +.BI "int ldap_control_create(const char *" oid ", int " iscritical ", struct berval *" value ", int " dupval ", LDAPControl **" ctrlp ");" .LP -.BI "LDAPControl *ldap_find_control(LDAP_CONST char *" OID ", LDAPControl **" ctrls ");" +.BI "LDAPControl *ldap_control_find( const char *" oid ", LDAPControl **" ctrls ", LDAPControl ***" nextctrlp ");" +.LP +.BI "LDAPControl *ldap_control_dup(LDAPControl *" ctrl ");" +.LP +.BI "LDAPControl **ldap_controls_dup(LDAPControl **" ctrls ");" .LP .BI "void ldap_control_free(LDAPControl *" ctrl ");" .LP .BI "void ldap_controls_free(LDAPControl **" ctrls ");" .SH DESCRIPTION These routines are used to manipulate structures used for LDAP controls. -.BR ldap_create_control () + +.BR ldap_control_create () creates a control with the specified .I OID using the contents of the -.I ber -parameter for the control value, if any. The +.I value +parameter for the control value, if any. The content of +.I value +is duplicated if +.I dupval +is non-zero. The .I iscritical -parameter should be non-zero for a critical control. The created control +parameter must be non-zero for a critical control. The created control is returned in the .I ctrlp -parameter. The routine returns +parameter. The routine returns .B LDAP_SUCCESS on success or some other error code on failure. -.BR ldap_find_control () -searches the +The content of +.IR value , +for supported control types, can be prepared using helpers provided +by this implementation of libldap, usually in the form +.BR "ldap_create__control_value" (). +Otherwise, it can be BER-encoded using the functionalities of liblber. + +.BR ldap_control_find () +searches the NULL-terminated .I ctrls array for a control whose OID matches the -.I OID -parameter. The routine returns a pointer to the control if found, +.I oid +parameter. The routine returns a pointer to the control if found, NULL otherwise. +If the parameter +.I nextctrlp +is not NULL, on return it will point to the next control +in the array, and can be passed to the +.BR ldap_control_find () +routine for subsequent calls, to find further occurrences of the same +control type. +The use of this function is discouraged; the recommended way of handling +controls in responses consists in going through the array of controls, +dealing with each of them in the returned order, since it could matter. + +.BR ldap_control_dup () +duplicates an individual control structure, and +.BR ldap_controls_dup () +duplicates a NULL-terminated array of controls. + .BR ldap_control_free () frees an individual control structure, and .BR ldap_controls_free () -frees an array of controls. +frees a NULL-terminated array of controls. + .SH SEE ALSO .BR ldap (3), .BR ldap_error (3) diff --git a/doc/man/man3/ldap_controls.3.links b/doc/man/man3/ldap_controls.3.links index 03cd358cc8..6c5248f641 100644 --- a/doc/man/man3/ldap_controls.3.links +++ b/doc/man/man3/ldap_controls.3.links @@ -1,4 +1,6 @@ -ldap_create_control.3 -ldap_find_control.3 +ldap_control_create.3 +ldap_control_find.3 +ldap_control_dup.3 +ldap_controls_dup.3 ldap_control_free.3 ldap_controls_free.3 diff --git a/doc/man/man3/ldap_first_message.3 b/doc/man/man3/ldap_first_message.3 index 66af6e7650..0eeadd77b5 100644 --- a/doc/man/man3/ldap_first_message.3 +++ b/doc/man/man3/ldap_first_message.3 @@ -3,8 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_first_message, ldap_next_message, ldap_count_messages \- Stepping -through messages in a result chain +ldap_first_message, ldap_next_message, ldap_count_messages \- Stepping through messages in a result chain .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS diff --git a/doc/man/man3/ldap_first_reference.3 b/doc/man/man3/ldap_first_reference.3 index b5b2822a35..ddaa836960 100644 --- a/doc/man/man3/ldap_first_reference.3 +++ b/doc/man/man3/ldap_first_reference.3 @@ -3,8 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_first_reference, ldap_next_reference, ldap_count_references \- Stepping -through continuation references in a result chain +ldap_first_reference, ldap_next_reference, ldap_count_references \- Stepping through continuation references in a result chain .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS diff --git a/doc/man/man3/ldap_get_option.3 b/doc/man/man3/ldap_get_option.3 index b98906d756..ab795520e5 100644 --- a/doc/man/man3/ldap_get_option.3 +++ b/doc/man/man3/ldap_get_option.3 @@ -80,7 +80,7 @@ and they cannot be NULL. Using a struct with seconds set to -1 results in an infinite timeout, which is the default. .TP .B LDAP_OPT_DEREF -Sets/gets the value that defines when alias deferencing must occur. +Sets/gets the value that defines when alias dereferencing must occur. .BR outvalue and .BR invalue @@ -187,7 +187,7 @@ the library duplicates the controls passed via .B LDAP_OPT_HOST_NAME Sets/gets a space-separated list of hosts to be contacted by the library when trying to establish a connection. -This is now deprecated in favour of +This is now deprecated in favor of .BR LDAP_OPT_URI . .BR outvalue must be a diff --git a/doc/man/man3/ldap_parse_sort_control.3 b/doc/man/man3/ldap_parse_sort_control.3 index 28813961ab..f2e5acd437 100644 --- a/doc/man/man3/ldap_parse_sort_control.3 +++ b/doc/man/man3/ldap_parse_sort_control.3 @@ -3,8 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_parse_sort_control \- Decodes the information returned from a search operation -that used a server-side sort control. +ldap_parse_sort_control \- Decode the information returned from a search operation that used a server-side sort control .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS diff --git a/doc/man/man3/ldap_parse_vlv_control.3 b/doc/man/man3/ldap_parse_vlv_control.3 index 522cc13c07..f0fa8d9969 100644 --- a/doc/man/man3/ldap_parse_vlv_control.3 +++ b/doc/man/man3/ldap_parse_vlv_control.3 @@ -3,8 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_parse_vlv_control \- Decodes the information returned from a search operation that -used a VLV (virtual list view) control. +ldap_parse_vlv_control \- Decode the information returned from a search operation that used a VLV (virtual list view) control .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS @@ -39,7 +38,7 @@ in this parameter. If this parameter is set to NULL, the context identifier is not returned. You should use this returned context in the next call to create a VLV control. When the berval structure is no longer needed, you should free the memory by calling the \fIber_bvfree function.e\fP -\fIerrcodep\fP is an output paremeter, which points to the result code returned +\fIerrcodep\fP is an output parameter, which points to the result code returned by the server. If this parameter is NULL, the result code is not returned. .LP See diff --git a/doc/man/man3/ldap_rename.3 b/doc/man/man3/ldap_rename.3 index 26d4264b9b..3cd48cc32c 100644 --- a/doc/man/man3/ldap_rename.3 +++ b/doc/man/man3/ldap_rename.3 @@ -49,7 +49,7 @@ structures that list the client controls to use with the search. .B ldap_rename works just like .B ldap_rename_s, -but the operation is asynchornous. It returns the message id of the request +but the operation is asynchronous. It returns the message id of the request it initiated. The result of this operation can be obtained by calling .BR ldap_result(3). .SH ERRORS diff --git a/doc/man/man3/ldap_result.3 b/doc/man/man3/ldap_result.3 index e86aecffd1..cae3a8d26d 100644 --- a/doc/man/man3/ldap_result.3 +++ b/doc/man/man3/ldap_result.3 @@ -27,8 +27,8 @@ The routine is used to wait for and return the result of an operation previously initiated by one of the LDAP asynchronous operation routines (e.g., -.BR ldap_search (3), -.BR ldap_modify (3), +.BR ldap_search_ext (3), +.BR ldap_modify_ext (3), etc.). Those routines all return -1 in case of error, and an invocation identifier upon successful initiation of the operation. The invocation identifier is picked by the library and is guaranteed to be @@ -94,7 +94,7 @@ The possible result types returned are: LDAP_RES_MODDN (0x6d) LDAP_RES_COMPARE (0x6f) LDAP_RES_EXTENDED (0x78) - LDAP_RES_EXTENDED_PARTIAL (0x79) + LDAP_RES_INTERMEDIATE (0x79) .fi .LP The @@ -103,7 +103,7 @@ routine is used to free the memory allocated for result(s) by .B ldap_result() or -.BR ldap_search_s (3) +.BR ldap_search_ext_s (3) and friends. It takes a pointer to the result or result chain to be freed and returns the type of the last message in the chain. @@ -126,7 +126,6 @@ and return -1 on error. .SH SEE ALSO .BR ldap (3), -.BR ldap_search (3), .BR ldap_first_message (3), .BR select (2) .SH ACKNOWLEDGEMENTS diff --git a/doc/man/man3/ldap_schema.3 b/doc/man/man3/ldap_schema.3 index 63b040ba91..5b794be401 100644 --- a/doc/man/man3/ldap_schema.3 +++ b/doc/man/man3/ldap_schema.3 @@ -3,14 +3,7 @@ .\" Copyright 2000-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_str2syntax, ldap_syntax2str, ldap_syntax2name, ldap_syntax_free, -ldap_str2matchingrule, ldap_matchingrule2str, ldap_matchingrule2name, -ldap_matchingrule_free, -ldap_str2attributetype, ldap_attributetype2str, -ldap_attributetype2name, ldap_attributetype_free, -ldap_str2objectclass, ldap_objectclass2str, ldap_objectclass2name, -ldap_objectclass_free, -ldap_scherr2str \- Schema definition handling routines +ldap_str2syntax, ldap_syntax2str, ldap_syntax2name, ldap_syntax_free, ldap_str2matchingrule, ldap_matchingrule2str, ldap_matchingrule2name, ldap_matchingrule_free, ldap_str2attributetype, ldap_attributetype2str, ldap_attributetype2name, ldap_attributetype_free, ldap_str2objectclass, ldap_objectclass2str, ldap_objectclass2name, ldap_objectclass_free, ldap_scherr2str \- Schema definition handling routines .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS diff --git a/doc/man/man3/ldap_search.3 b/doc/man/man3/ldap_search.3 index f17b62f9e8..83374caeae 100644 --- a/doc/man/man3/ldap_search.3 +++ b/doc/man/man3/ldap_search.3 @@ -83,7 +83,7 @@ The description "*" (LDAP_ALL_USER_ATTRIBUTES) may be used to request all user attributes to be returned. The description "+"(LDAP_ALL_OPERATIONAL_ATTRIBUTES) may be used to request all operational attributes to be returned. Note that this -requires the server to suppor the LDAP All Operational Attribute +requires the server to support the LDAP All Operational Attribute extension. To request no attributes, the description "1.1" (LDAP_NO_ATTRS) should be listed by itself. diff --git a/doc/man/man3/ldap_sort.3 b/doc/man/man3/ldap_sort.3 index 1f4cfa4bf7..10a92e1659 100644 --- a/doc/man/man3/ldap_sort.3 +++ b/doc/man/man3/ldap_sort.3 @@ -3,7 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -LDAP sorting routines (deprecated) +ldap_sort_entries, ldap_sort_values, ldap_sort_strcasecmp \- LDAP sorting routines (deprecated) .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH DESCRIPTION diff --git a/doc/man/man3/ldap_sync.3 b/doc/man/man3/ldap_sync.3 index 17b97536c4..9cb1436c02 100644 --- a/doc/man/man3/ldap_sync.3 +++ b/doc/man/man3/ldap_sync.3 @@ -10,11 +10,11 @@ OpenLDAP LDAP (libldap, -lldap) .nf .B #include .LP -.BI "int ldap_sync_init(ldap_sync_t *" ls ", int " mode ", int " cancel ");" +.BI "int ldap_sync_init(ldap_sync_t *" ls ", int " mode ");" .LP -.BI "int ldap_sync_init_refresh_only(ldap_sync_t *" ls ", int " cancel ");" +.BI "int ldap_sync_init_refresh_only(ldap_sync_t *" ls ");" .LP -.BI "int ldap_sync_init_refresh_and_persist(ldap_sync_t *" ls ", int " cancel ");" +.BI "int ldap_sync_init_refresh_and_persist(ldap_sync_t *" ls ");" .LP .BI "int ldap_sync_poll(ldap_sync_t *" ls ");" .LP @@ -198,7 +198,8 @@ to indicate that the refresh phase of refreshAndPersist is over, and the client should start polling. Except for the .BR LDAP_SYNC_CAPI_PRESENTS_IDSET -and LDAP_SYNC_CAPI_DELETES_IDSET +and +.BR LDAP_SYNC_CAPI_DELETES_IDSET cases, .BR syncUUIDs is NULL. @@ -239,7 +240,7 @@ structure, and sets appropriate values for some members. After that, the caller is responsible for setting up the connection (member .BR ls_ld ), -evetually setting up transport security (TLS), +eventually setting up transport security (TLS), for binding and any other initialization. The caller must also fill all the documented search-related fields of the diff --git a/doc/man/man3/ldap_url.3 b/doc/man/man3/ldap_url.3 index 7a1662bb3f..d1045245a4 100644 --- a/doc/man/man3/ldap_url.3 +++ b/doc/man/man3/ldap_url.3 @@ -3,9 +3,7 @@ .\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -ldap_is_ldap_url, -ldap_url_parse, -ldap_free_urldesc \- LDAP Uniform Resource Locator routines +ldap_is_ldap_url, ldap_url_parse, ldap_free_urldesc \- LDAP Uniform Resource Locator routines .SH LIBRARY OpenLDAP LDAP (libldap, -lldap) .SH SYNOPSIS diff --git a/doc/man/man5/ldap.conf.5 b/doc/man/man5/ldap.conf.5 index b581869638..df5604be81 100644 --- a/doc/man/man5/ldap.conf.5 +++ b/doc/man/man5/ldap.conf.5 @@ -278,6 +278,7 @@ certificates in separate individual files. The .B TLS_CACERT is always used before .B TLS_CACERTDIR. +This parameter is ignored with GNUtls. .TP .B TLS_CERT Specifies the file that contains the client certificate. @@ -300,6 +301,7 @@ e.g., HIGH:MEDIUM:+SSLv2. Specifies the file to obtain random bits from when /dev/[u]random is not available. Generally set to the name of the EGD/PRNGD socket. The environment variable RANDFILE can also be used to specify the filename. +This parameter is ignored with GNUtls. .TP .B TLS_REQCERT Specifies what checks to perform on server certificates in a TLS session, @@ -332,7 +334,7 @@ Specifies if the Certificate Revocation List (CRL) of the CA should be used to verify if the server certificates have not been revoked. This requires .B TLS_CACERTDIR -parameter to be set. +parameter to be set. This parameter is ignored with GNUtls. .B can be specified as one of the following keywords: .RS @@ -346,6 +348,11 @@ Check the CRL of the peer certificate .B all Check the CRL for a whole certificate chain .RE +.TP +.B TLS_CRLFILE +Specifies the file containing a Certificate Revocation List to be used +to verify if the server certificates have not been revoked. This +parameter is only supported with GNUtls. .SH "ENVIRONMENT VARIABLES" .TP LDAPNOINIT diff --git a/doc/man/man5/ldif.5 b/doc/man/man5/ldif.5 index 0a892983c3..dfc44f5afb 100644 --- a/doc/man/man5/ldif.5 +++ b/doc/man/man5/ldif.5 @@ -269,6 +269,8 @@ commands. .BR ldapadd (1), .BR ldapmodify (1), .BR slapadd (8), +.BR slapcat (8), +.BR slapd-ldif (5), .BR slapd.replog (5). .LP "LDAP Data Interchange Format," Good, G., RFC 2849. diff --git a/doc/man/man5/slapd-bdb.5 b/doc/man/man5/slapd-bdb.5 index 4fda2c35db..8f59a1565e 100644 --- a/doc/man/man5/slapd-bdb.5 +++ b/doc/man/man5/slapd-bdb.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -\fBslapd-bdb\fP, \fBslapd-hdb\fP \- Berkeley DB backends to \fBslapd\fP +slapd-bdb, slapd-hdb \- Berkeley DB backends to slapd .SH SYNOPSIS .B ETCDIR/slapd.conf .SH DESCRIPTION @@ -12,7 +12,7 @@ The \fBbdb\fP backend to is the recommended primary backend for a normal .B slapd database. -It uses the Sleepycat Berkeley DB (BDB) package to store data. +It uses the Oracle Berkeley DB (BDB) package to store data. It makes extensive use of indexing and caching to speed data access. .LP \fBhdb\fP is a variant of the \fBbdb\fP backend that uses a @@ -107,6 +107,11 @@ results if the data comes from a transaction that is later aborted. In this case, the modified data is discarded and a subsequent search will return a different result. .TP +.BI dncachesize \ +Specify the maximum number of DNs in the in-memory DN cache. The +default is twice the \fBcachesize\fP. Ideally this cache should be +large enough to contain the DNs of every entry in the database. +.TP .BI idlcachesize \ Specify the size of the in-memory index cache, in index slots. The default is zero. A larger value will speed up frequent searches of @@ -225,3 +230,6 @@ Berkeley DB configuration file Berkeley DB documentation. .SH ACKNOWLEDGEMENTS .so ../Project +Originally begun by Kurt Zeilenga. Caching mechanisms originally designed +by Jong-Hyuk Choi. Completion and subsequent work, as well as +back-hdb, by Howard Chu. diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 3a375546cb..146dc30131 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapd-config \- configuration backend +slapd-config \- configuration backend to slapd .SH SYNOPSIS ETCDIR/slapd.d .SH DESCRIPTION @@ -488,6 +488,11 @@ see .B minssf option description. The default is 71. .TP +.B olcLogFile: +Specify a file for recording debug log messages. By default these messages +only go to stderr and are not recorded anywhere else. Specifying a logfile +copies messages to both stderr and the logfile. +.TP .B olcLogLevel: [...] Specify the level at which debugging statements and operation statistics should be syslogged (currently logged to the @@ -496,8 +501,7 @@ LOG_LOCAL4 facility). They must be considered subsystems rather than increasingly verbose log levels. Some messages with higher priority are logged regardless -of the configured loglevel as soon as some logging is configured, -otherwise anything is logged at all. +of the configured loglevel as soon as any logging is configured. Log levels are additive, and available levels are: .RS .RS @@ -668,40 +672,6 @@ Specify the referral to pass back when .BR slapd (8) cannot find a local database to handle a request. If multiple values are specified, each url is provided. -.\" slurpd-related keywords are all deprecated -.\".TP -.\".B replica-argsfile -.\"The ( absolute ) name of a file that will hold the -.\".B slurpd -.\"server's command line options -.\"if started without the debugging command line option. -.\"If it appears after a -.\".B replogfile -.\"directive, the args file is specific to the -.\".BR slurpd (8) -.\"instance that handles that replication log. -.\".TP -.\".B replica-pidfile -.\"The ( absolute ) name of a file that will hold the -.\".B slurpd -.\"server's process ID ( see -.\".BR getpid (2) -.\") if started without the debugging command line option. -.\"If it appears after a -.\".B replogfile -.\"directive, the pid file is specific to the -.\".BR slurpd (8) -.\"instance that handles that replication log. -.\".TP -.\".B replicationinterval -.\"The number of seconds -.\".B slurpd -.\"waits before checking the replogfile for changes. -.\"If it appears after a -.\".B replogfile -.\"directive, the replication interval is specific to the -.\".BR slurpd (8) -.\"instance that handles that replication log. .TP .B olcReverseLookup: TRUE | FALSE Enable/disable client name unverified reverse lookup (default is @@ -712,6 +682,14 @@ if compiled with --enable-rlookups). Specify the name of an LDIF(5) file containing user defined attributes for the root DSE. These attributes are returned in addition to the attributes normally produced by slapd. + +The root DSE is an entry with information about the server and its +capabilities, in operational attributes. +It has the empty DN, and can be read with e.g.: +.ti +4 +ldapsearch -x -b "" -s base "+" +.br +See RFC 4512 section 5.1 for details. .TP .B olcSaslHost: Used to specify the fully qualified domain name used for SASL processing. @@ -811,9 +789,17 @@ Permits configuring what ciphers will be accepted and the preference order. olcTLSCipherSuite: HIGH:MEDIUM:+SSLv2 -To check what ciphers a given spec selects, use: +To check what ciphers a given spec selects in OpenSSL, use: + +.nf + openssl ciphers -v +.fi -openssl ciphers -v +To obtain the list of ciphers in GNUtls use: + +.nf + gnutls-cli -l +.fi .TP .B olcTLSCACertificateFile: Specifies the file that contains certificates for all of the Certificate @@ -825,7 +811,8 @@ will recognize. Specifies the path of a directory that contains Certificate Authority certificates in separate individual files. Usually only one of this or the olcTLSCACertificateFile is defined. If both are specified, both -locations will be used. +locations will be used. This directive is not supported +when using GNUtls. .TP .B olcTLSCertificateFile: Specifies the file that contains the @@ -851,12 +838,14 @@ them will be processed. Note that setting this option may also enable Anonymous Diffie-Hellman key exchanges in certain non-default cipher suites. You should append "!ADH" to your cipher suites if you have changed them from the default, otherwise no certificate exchanges or verification will -be done. +be done. When using GNUtls these parameters are always generated randomly +so this directive is ignored. .TP .B olcTLSRandFile: Specifies the file to obtain random bits from when /dev/[u]random is not available. Generally set to the name of the EGD/PRNGD socket. The environment variable RANDFILE can also be used to specify the filename. +This directive is ignored with GNUtls. .TP .B olcTLSVerifyClient: Specifies what checks to perform on client certificates in an @@ -898,7 +887,7 @@ Specifies if the Certificate Revocation List (CRL) of the CA should be used to verify if the client certificates have not been revoked. This requires .B olcTLSCACertificatePath -parameter to be set. +parameter to be set. This parameter is ignored with GNUtls. .B can be specified as one of the following keywords: .RS @@ -912,6 +901,11 @@ Check the CRL of the peer certificate .B all Check the CRL for a whole certificate chain .RE +.TP +.B olcTLSCRLFile: +Specifies a file containing a Certificate Revocation List to be used +for verifying that certificates have not been revoked. This parameter +is only valid when using GNUtls. .SH DYNAMIC MODULE OPTIONS If .B slapd @@ -1216,6 +1210,13 @@ which they are defined. They are supported by every type of backend. All of the Global Database Options may also be used here. .TP +.B olcHidden: TRUE | FALSE +Controls whether the database will be used to answer +queries. A database that is hidden will never be +selected to answer any queries, and any suffix configured +on the database will be ignored in checks for conflicts +with other databases. By default, olcHidden is FALSE. +.TP .B olcLastMod: TRUE | FALSE Controls whether .B slapd @@ -1451,90 +1452,15 @@ resolve an entry, used to avoid infinite alias loops. The default is 1. This option puts a replica database into "mirror" mode. Update operations will be accepted from any user, not just the updatedn. The database must already be configured as syncrepl consumer -before this keyword may be set. This mode must be used with extreme -care, as it does not offer any consistency guarantees. This feature -is intended to be used with an external frontend that guarantees that -writes are only directed to a single master, switching to an alternate -server only if the original master goes down. +before this keyword may be set. This mode also requires a +.B olcServerID +(see above) to be configured. By default, this setting is FALSE. .TP .B olcPlugin: [] Configure a SLAPI plugin. See the .BR slapd.plugin (5) manpage for more details. -.\".HP -.\".hy 0 -.\".B replica uri=ldap[s]://[:port]|host=[:port] -.\".B [starttls=yes|critical] -.\".B [suffix= [...]] -.\".B bindmethod=simple|sasl [binddn=] [credentials=] -.\".B [saslmech=] [secprops=] [realm=] -.\".B [authcId=] [authzId=] -.\".B [attrs[!]=] -.\".RS -.\"Specify a replication site for this database. Refer to the "OpenLDAP -.\"Administrator's Guide" for detailed information on setting up a replicated -.\".B slapd -.\"directory service. Zero or more -.\".B suffix -.\"instances can be used to select the subtrees that will be replicated -.\"(defaults to all the database). -.\".B host -.\"is deprecated in favor of the -.\".B uri -.\"option. -.\".B uri -.\"allows the replica LDAP server to be specified as an LDAP URI. -.\"A -.\".B bindmethod -.\"of -.\".B simple -.\"requires the options -.\".B binddn -.\"and -.\".B credentials -.\"and should only be used when adequate security services -.\"(e.g TLS or IPSEC) are in place. A -.\".B bindmethod -.\"of -.\".B sasl -.\"requires the option -.\".B saslmech. -.\"Specific security properties (as with the -.\".B sasl-secprops -.\"keyword above) for a SASL bind can be set with the -.\".B secprops -.\"option. A non-default SASL realm can be set with the -.\".B realm -.\"option. -.\"If the -.\".B mechanism -.\"will use Kerberos, a kerberos instance should be given in -.\".B authcId. -.\"An -.\".B attr list -.\"can be given after the -.\".B attrs -.\"keyword to allow the selective replication of the listed attributes only; -.\"if the optional -.\".B ! -.\"mark is used, the list is considered exclusive, i.e. the listed attributes -.\"are not replicated. -.\"If an objectClass is listed, all the related attributes -.\"are (are not) replicated. -.\".RE -.\".TP -.\".B replogfile -.\"Specify the name of the replication log file to log changes to. -.\"The replication log is typically written by -.\".BR slapd (8) -.\"and read by -.\".BR slurpd (8). -.\"See -.\".BR slapd.replog (5) -.\"for more information. The specified file should be located -.\"in a directory with limited read/write/execute access as the replication -.\"logs may contain sensitive information. .TP .B olcRootDN: Specify the distinguished name that is not subject to access control @@ -1807,9 +1733,8 @@ ignored. This option is only applicable in a slave database. It specifies the DN permitted to update (subject to access controls) -the replica (typically, this is the DN -.BR slurpd (8) -binds to update the replica). Generally, this DN +the replica. It is only needed in certain push-mode +replication scenarios. Generally, this DN .I should not be the same as the .B rootdn @@ -1954,8 +1879,7 @@ default slapd configuration directory .BR slapdn (8), .BR slapindex (8), .BR slappasswd (8), -.BR slaptest (8), -.BR slurpd (8). +.BR slaptest (8). .LP "OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) .SH ACKNOWLEDGEMENTS diff --git a/doc/man/man5/slapd-ldap.5 b/doc/man/man5/slapd-ldap.5 index 847ea6d657..ee9fbffdd4 100644 --- a/doc/man/man5/slapd-ldap.5 +++ b/doc/man/man5/slapd-ldap.5 @@ -429,6 +429,13 @@ or when chasing a referral, if is set to .IR yes . +.TP +.B session\-tracking\-request {NO|yes} +Adds session tracking control for all requests. +The client's IP and hostname, and the identity associated to each request, +if known, are sent to the remote server for informational purposes. +This directive is incompatible with setting \fIprotocol\-version\fP to 2. + .TP .B single\-conn {NO|yes} Discards current cached connection when the client rebinds. diff --git a/doc/man/man5/slapd-ldbm.5 b/doc/man/man5/slapd-ldbm.5 index 336d0ae46a..45856458da 100644 --- a/doc/man/man5/slapd-ldbm.5 +++ b/doc/man/man5/slapd-ldbm.5 @@ -3,141 +3,18 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapd-ldbm \- LDBM backend to slapd +slapd-ldbm \- Discontinued LDBM backend to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION -The LDBM backend to -.BR slapd (8) -is an easy\-to\-configure but obsolete database backend. It does not -offer the data durability features of the BDB and HDB backends and -hence is considered deprecated in favor of these robust backends. -LDBM uses lightweight non\-transactional data interfaces, such as those -provided by GDBM or Berkeley DB, to store data. It makes extensive -use of indexing and caching to speed data access. -.SH CONFIGURATION -These -.B slapd.conf -options apply to the LDBM backend database. -That is, they must follow a "database ldbm" line and come before any -subsequent "backend" or "database" lines. -Other database options are described in the -.BR slapd.conf (5) -manual page. -.TP -.B cachesize -Specify the size in entries of the in-memory cache maintained -by the LDBM backend database instance. -The default is 1000 entries. -.TP -.B dbcachesize -Specify the size in bytes of the in-memory cache associated with each -open index file. -If not supported by the underlying database method, this option is -ignored without comment. -The default is 100000 bytes. -.TP -.B dbnolocking -Specify that no database locking should be performed. -Enabling this option may improve performance at the expense of data security. -Do NOT run any slap tools while slapd is running. -.TP -.B dbnosync -Specify that on-disk database contents should not be immediately -synchronized with in memory changes. -Enabling this option may improve performance at the expense of data -security. -.TP -.B dbsync -Flush dirty database buffers to disk every -.B -seconds. -Implies -.B dbnosync -(ie. individual updates are no longer written to disk). -It attempts to avoid syncs during periods of peak activity by waiting -.B -seconds if the server is busy, repeating this delay up to -.B -times before proceeding. -It is an attempt to provide higher write performance with some amount -of data security. -Note that it may still be possible to get an inconsistent database if -the underlying engine fills its cache and writes out individual pages -and slapd crashes or is killed before the next sync. -.B -and -.B -are optional and default to -.B 12 -and -.B 5 -respectively, giving a total elapsed delay of 60 seconds before a sync -will occur. -.B -may be zero, and -.B -must be 1 or greater. -.TP -.B directory -Specify the directory where the LDBM files containing this database and -associated indexes live. -A separate directory must be specified for each database. -The default is -.BR LOCALSTATEDIR/openldap-data . -.TP -.B -index {|default} [pres,eq,approx,sub,] -Specify the indexes to maintain for the given attribute (or -list of attributes). -Some attributes only support a subset of indexes. -If only an is given, the indices specified for \fBdefault\fR -are maintained. -Note that setting a default does not imply that all attributes will be -indexed. Also, for best performance, an -.B eq -index should always be configured for the -.B objectClass -attribute. +LDBM was the original database backend to +.BR slapd (8), +and was supported up to OpenLDAP 2.3. +It has been superseded by the more robust BDB and HDB backends. -A number of special index parameters may be specified. -The index type -.B sub -can be decomposed into -.BR subinitial , -.BR subany ,\ and -.B subfinal -indices. -The special type -.B notags -(or -.BR nolang ) -may be specified to disallow use of this index by subtypes with tagging -options (such as language options). -The special type -.B nosubtypes -may be specified to disallow use of this index by named subtypes. -Note: changing index settings requires rebuilding indices, see -.BR slapindex (8). -.TP -.B mode -Specify the file protection mode that newly created database -index files should have. -The default is 0600. -.SH ACCESS CONTROL -The -.B ldbm -backend honors access control semantics as indicated in -.BR slapd.access (5). -.SH FILES -.TP -ETCDIR/slapd.conf -default slapd configuration file .SH SEE ALSO -.BR slapd.conf (5), .BR slapd (8), -.BR slapadd (8), -.BR slapcat (8), -.BR slapindex (8). +.BR slapd-bdb (5), +.BR slapd.backends (5). .SH ACKNOWLEDGEMENTS .so ../Project diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index 46e9fb5c14..e2c5bbe0e2 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -8,7 +8,7 @@ .\" and maybe manual pages for librewrite. .\" .SH NAME -slapd-meta \- metadirectory backend +slapd-meta \- metadirectory backend to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -172,6 +172,15 @@ or when chasing a referral, if is set to .IR yes . +.TP +.B session\-tracking\-request {NO|yes} +Adds session tracking control for all requests. +The client's IP and hostname, and the identity associated to each request, +if known, are sent to the remote server for informational purposes. +This directive is incompatible with setting \fIprotocol\-version\fP to 2. +If set before any target specification, it affects all targets, unless +overridden by any per-target directive. + .TP .B single\-conn {NO|yes} Discards current cached connection when the client rebinds. @@ -532,7 +541,7 @@ The rule .LP .RS .nf -access to dn="" attr= +access to dn="" attrs= by dnattr= read by * none .fi diff --git a/doc/man/man5/slapd-monitor.5 b/doc/man/man5/slapd-monitor.5 index b4894c34a1..e5faa0dd66 100644 --- a/doc/man/man5/slapd-monitor.5 +++ b/doc/man/man5/slapd-monitor.5 @@ -3,8 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -.B slapd-monitor -\- Monitor backend to slapd +slapd-monitor \- Monitor backend to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapd-null.5 b/doc/man/man5/slapd-null.5 index 90d0437509..8a28a51040 100644 --- a/doc/man/man5/slapd-null.5 +++ b/doc/man/man5/slapd-null.5 @@ -39,7 +39,7 @@ Other database options are described in the manual page. .TP .B bind -Allow binds as DNs in this backend's suffix. +Allow binds as any DN in this backend's suffix, with any password. The default is "off". .SH EXAMPLE Here is a possible slapd.conf extract using the Null backend: diff --git a/doc/man/man5/slapd-relay.5 b/doc/man/man5/slapd-relay.5 index 8aeead99c2..b59d215c30 100644 --- a/doc/man/man5/slapd-relay.5 +++ b/doc/man/man5/slapd-relay.5 @@ -12,8 +12,8 @@ running in the same instance into a virtual naming context, with attributeType and objectClass manipulation, if required. It requires the -.B rwm -.BR overlay . +.BR slapo-rwm (5) +overlay. .LP This backend and the above mentioned overlay are experimental. .SH CONFIGURATION @@ -26,27 +26,30 @@ Other database options are described in the .BR slapd.conf (5) manual page; only the .B suffix -directive is required by the +directive is allowed by the .I relay backend. .TP -.B relay [massage] +.B relay The naming context of the database that is presented under a virtual naming context. The presence of this directive implies that one specific database, i.e. the one serving the .BR "real naming context" , will be presented under a virtual naming context. -This directive automatically instantiates the -.IR "rwm overlay" . -If the optional -.B massage -keyword is present, the suffix massaging is automatically -configured as well; otherwise, specific massaging instructions -are required by means of the -.I rewrite -directives described in -.BR slapo-rwm (5). + +.SH MASSAGING +The +.B relay +database does not automatically rewrite the naming context +of requests and responses. +For this purpose, the +.BR slapo-rwm (5) +overlay must be explicitly instantiated, and configured +as appropriate. +Usually, the +.B rwm-suffixmassage +directive suffices if only naming context rewriting is required. .SH ACCESS RULES One important issue is that access rules are based on the identity @@ -57,7 +60,7 @@ real naming context. Moreover, since .B back-relay bypasses the real database frontend operations by short-circuiting -operations thru the internal backend API, the original database +operations through the internal backend API, the original database access rules do not apply but in selected cases, i.e. when the backend itself applies access control. As a consequence, the instances of the relay database must provide @@ -88,29 +91,26 @@ Another possibility is to map the same operation to different databases based on details of the virtual naming context, e.g. groups on one database and persons on another. .LP -.SH Caveats -The -.B rwm overlay -is experimental. -.LP .SH EXAMPLES To implement a plain virtual naming context mapping that refers to a single database, use .LP .nf - database relay - suffix "dc=virtual,dc=naming,dc=context" - relay "dc=real,dc=naming,dc=context" massage + database relay + suffix "dc=virtual,dc=naming,dc=context" + relay "dc=real,dc=naming,dc=context" + overlay rwm + rwm-suffixmassage "dc=real,dc=naming,dc=context" .fi .LP To implement a plain virtual naming context mapping that looks up the real naming context for each operation, use .LP .nf - database relay - suffix "dc=virtual,dc=naming,dc=context" - overlay rwm - suffixmassage "dc=real,dc=naming,dc=context" + database relay + suffix "dc=virtual,dc=naming,dc=context" + overlay rwm + rwm-suffixmassage "dc=real,dc=naming,dc=context" .fi .LP This is useful, for instance, to relay different databases that @@ -122,39 +122,43 @@ the virtual to the real naming context, but not the results back from the real to the virtual naming context, use .LP .nf - database relay - suffix "dc=virtual,dc=naming,dc=context" - relay "dc=real,dc=naming,dc=context" - rewriteEngine on - rewriteContext default - rewriteRule "dc=virtual,dc=naming,dc=context" - "dc=real,dc=naming,dc=context" ":@" - rewriteContext searchFilter - rewriteContext searchEntryDN - rewriteContext searchAttrDN - rewriteContext matchedDN + database relay + suffix "dc=virtual,dc=naming,dc=context" + relay "dc=real,dc=naming,dc=context" + overlay rwm + rwm-rewriteEngine on + rwm-rewriteContext default + rwm-rewriteRule "dc=virtual,dc=naming,dc=context" + "dc=real,dc=naming,dc=context" ":@" + rwm-rewriteContext searchFilter + rwm-rewriteContext searchEntryDN + rwm-rewriteContext searchAttrDN + rwm-rewriteContext matchedDN .fi .LP -Note that the virtual database is bound to a single real database, -so the -.B rwm overlay -is automatically instantiated, but the rewrite rules -are written explicitly to map all the virtual to real -naming context data flow, but none of the real to virtual. +Note that the +.BR slapo-rwm (5) +overlay is instantiated, but the rewrite rules are written explicitly, +rather than automatically as with the +.B rwm-suffixmassage +statement, to map all the virtual to real naming context data flow, +but none of the real to virtual. .LP Access rules: .LP .nf - database bdb - suffix "dc=example,dc=com" + database bdb + suffix "dc=example,dc=com" # skip... access to dn.subtree="dc=example,dc=com" by dn.exact="cn=Supervisor,dc=example,dc=com" write by * read - database relay - suffix "o=Example,c=US" - relay "dc=example,dc=com" massage + database relay + suffix "o=Example,c=US" + relay "dc=example,dc=com" + overlay rwm + rwm-suffixmassage "dc=example,dc=com" # skip ... access to dn.subtree="o=Example,c=US" by dn.exact="cn=Supervisor,dc=example,dc=com" write diff --git a/doc/man/man5/slapd-sql.5 b/doc/man/man5/slapd-sql.5 index 454f63f46d..59e91ca809 100644 --- a/doc/man/man5/slapd-sql.5 +++ b/doc/man/man5/slapd-sql.5 @@ -100,7 +100,7 @@ see \fBupper_func\fP, \fBupper_needs_cast\fP, \fBconcat_pattern\fP and \fBstrcast_func\fP in "HELPER CONFIGURATION" for details. .TP -.B use_subtree_shortcut { NO | yes } +.B use_subtree_shortcut { YES | no } Do not use the subtree condition when the searchBase is the database suffix, and the scope is subtree; rather collect all entries. @@ -654,7 +654,7 @@ A directoryString value of the form "__First___Last_" (where underscores mean spaces, ASCII 0x20 char) corresponds to its prettified counterpart "First_Last"; this is not currently honored by back-sql if non-prettified data is written via RDBMS; -when non-prettified data is written thru back-sql, the prettified +when non-prettified data is written through back-sql, the prettified values are actually used instead. .LP diff --git a/doc/man/man5/slapd.access.5 b/doc/man/man5/slapd.access.5 index 75450bd242..2129e58e83 100644 --- a/doc/man/man5/slapd.access.5 +++ b/doc/man/man5/slapd.access.5 @@ -10,9 +10,7 @@ The .BR slapd.conf (5) file contains configuration information for the .BR slapd (8) -daemon. This configuration file is also used by the -.BR slurpd (8) -replication daemon and by the SLAPD tools +daemon. This configuration file is also used by the SLAPD tools .BR slapacl (8), .BR slapadd (8), .BR slapauth (8), diff --git a/doc/man/man5/slapd.backends.5 b/doc/man/man5/slapd.backends.5 index c5801ad31f..887c499c14 100644 --- a/doc/man/man5/slapd.backends.5 +++ b/doc/man/man5/slapd.backends.5 @@ -22,7 +22,7 @@ manual pages. .B bdb This is the recommended primary backend for a normal slapd database. It takes care to configure it properly. -It uses the transactional database interface of the Sleepycat Berkeley +It uses the transactional database interface of the Oracle Berkeley DB (BDB) package to store data. .TP .B config diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index e6d75395b9..e5c5a1cc2e 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -11,9 +11,7 @@ The file .B ETCDIR/slapd.conf contains configuration information for the .BR slapd (8) -daemon. This configuration file is also used by the -.BR slurpd (8) -replication daemon and by the SLAPD tools +daemon. This configuration file is also used by the SLAPD tools .BR slapacl (8), .BR slapadd (8), .BR slapauth (8), @@ -497,13 +495,6 @@ for the segments of a filter string that are processed for a subany index lookup. The default is 2. For example, with the default values, a search using this filter "cn=*abcdefgh*" would generate index lookups for "abcd", "cdef", and "efgh". - -.\"-- NEW_LOGGING option -- -.\".TP -.\".B logfile -.\"Specify a file for recording debug log messages. By default these messages -.\"only go to stderr and are not recorded anywhere else. Specifying a logfile -.\"copies messages to both stderr and the logfile. .TP .B localSSF Specifies the Security Strength Factor (SSF) to be given local LDAP sessions, @@ -513,6 +504,11 @@ see .B minssf option description. The default is 71. .TP +.B logfile +Specify a file for recording debug log messages. By default these messages +only go to stderr and are not recorded anywhere else. Specifying a logfile +copies messages to both stderr and the logfile. +.TP .B loglevel [...] Specify the level at which debugging statements and operation statistics should be syslogged (currently logged to the @@ -521,8 +517,7 @@ LOG_LOCAL4 facility). They must be considered subsystems rather than increasingly verbose log levels. Some messages with higher priority are logged regardless -of the configured loglevel as soon as some logging is configured, -otherwise anything is logged at all. +of the configured loglevel as soon as any logging is configured. Log levels are additive, and available levels are: .RS .RS @@ -562,7 +557,7 @@ access control list processing .TP .B 256 .B (0x100 stats) -stats log connections/operations/results +connections, LDAP operations, results (recommended) .TP .B 512 .B (0x200 stats2) @@ -614,10 +609,14 @@ The keyword .BR none , or the equivalent integer representation, causes those messages that are logged regardless of the configured loglevel to be logged. -In fact, if no loglevel (or a 0 level) is defined, no logging occurs, +In fact, if loglevel is set to 0, no logging occurs, so at least the .B none level is required to have high priority messages logged. + +The loglevel defaults to \fBstats\fP. +This level should usually also be included when using other loglevels, to +help analyze the logs. .RE .TP .B moduleload @@ -723,39 +722,6 @@ Specify the referral to pass back when cannot find a local database to handle a request. If specified multiple times, each url is provided. .TP -.B replica-argsfile -The ( absolute ) name of a file that will hold the -.B slurpd -server's command line options -if started without the debugging command line option. -If it appears after a -.B replogfile -directive, the args file is specific to the -.BR slurpd (8) -instance that handles that replication log. -.TP -.B replica-pidfile -The ( absolute ) name of a file that will hold the -.B slurpd -server's process ID ( see -.BR getpid (2) -) if started without the debugging command line option. -If it appears after a -.B replogfile -directive, the pid file is specific to the -.BR slurpd (8) -instance that handles that replication log. -.TP -.B replicationinterval -The number of seconds -.B slurpd -waits before checking the replogfile for changes. -If it appears after a -.B replogfile -directive, the replication interval is specific to the -.BR slurpd (8) -instance that handles that replication log. -.TP .B require Specify a set of conditions (separated by white space) to require (default none). @@ -788,6 +754,14 @@ if compiled with --enable-rlookups). Specify the name of an LDIF(5) file containing user defined attributes for the root DSE. These attributes are returned in addition to the attributes normally produced by slapd. + +The root DSE is an entry with information about the server and its +capabilities, in operational attributes. +It has the empty DN, and can be read with e.g.: +.ti +4 +ldapsearch -x -b "" -s base "+" +.br +See RFC 4512 section 5.1 for details. .TP .B sasl-host Used to specify the fully qualified domain name used for SASL processing. @@ -880,7 +854,9 @@ factor is measure of security provided by the underlying transport, e.g. ldapi:// (and eventually IPSEC). It is not normally used. .TP .B serverID [] -Specify an integer ID from 0 to 4095 for this server. These IDs are +Specify an integer ID from 0 to 4095 for this server (limited +to 3 hexadecimal digits). +These IDs are required when using multimaster replication and each master must have a unique ID. If the URL is provided, this directive may be specified multiple times, providing a complete list of participating servers @@ -957,7 +933,16 @@ TLSCipherSuite HIGH:MEDIUM:+SSLv2 To check what ciphers a given spec selects, use: -openssl ciphers -v +.nf + openssl ciphers -v +.fi + +To obtain the list of ciphers in GNUtls use: + +.nf + gnutls-cli -l +.fi + .TP .B TLSCACertificateFile Specifies the file that contains certificates for all of the Certificate @@ -968,7 +953,8 @@ will recognize. .B TLSCACertificatePath Specifies the path of a directory that contains Certificate Authority certificates in separate individual files. Usually only one of this -or the TLSCACertificateFile is used. +or the TLSCACertificateFile is used. This directive is not supported +when using GNUtls. .TP .B TLSCertificateFile Specifies the file that contains the @@ -991,12 +977,14 @@ them will be processed. Note that setting this option may also enable Anonymous Diffie-Hellman key exchanges in certain non-default cipher suites. You should append "!ADH" to your cipher suites if you have changed them from the default, otherwise no certificate exchanges or verification will -be done. +be done. When using GNUtls these parameters are always generated randomly so +this directive is ignored. .TP .B TLSRandFile Specifies the file to obtain random bits from when /dev/[u]random is not available. Generally set to the name of the EGD/PRNGD socket. The environment variable RANDFILE can also be used to specify the filename. +This directive is ignored with GNUtls. .TP .B TLSVerifyClient Specifies what checks to perform on client certificates in an @@ -1038,7 +1026,7 @@ Specifies if the Certificate Revocation List (CRL) of the CA should be used to verify if the client certificates have not been revoked. This requires .B TLSCACertificatePath -parameter to be set. +parameter to be set. This directive is ignored with GNUtls. .B can be specified as one of the following keywords: .RS @@ -1052,6 +1040,11 @@ Check the CRL of the peer certificate .B all Check the CRL for a whole certificate chain .RE +.TP +.B TLSCRLFile +Specifies a file containing a Certificate Revocation List to be used +for verifying that certificates have not been revoked. This directive is +only valid when using GNUtls. .SH GENERAL BACKEND OPTIONS Options in this section only apply to the configuration file section for the specified backend. They are supported by every @@ -1065,7 +1058,6 @@ should be one of .BR dnssrv , .BR hdb , .BR ldap , -.BR ldbm , .BR ldif , .BR meta , .BR monitor , @@ -1095,7 +1087,6 @@ should be one of .BR dnssrv , .BR hdb , .BR ldap , -.BR ldbm , .BR ldif , .BR meta , .BR monitor , @@ -1108,6 +1099,13 @@ or .BR sql , depending on which backend will serve the database. .TP +.B hidden on | off +Controls whether the database will be used to answer +queries. A database that is hidden will never be +selected to answer any queries, and any suffix configured +on the database will be ignored in checks for conflicts +with other databases. By default, hidden is off. +.TP .B lastmod on | off Controls whether .B slapd @@ -1342,12 +1340,10 @@ resolve an entry, used to avoid infinite alias loops. The default is 1. .B mirrormode on | off This option puts a replica database into "mirror" mode. Update operations will be accepted from any user, not just the updatedn. The -database must already be configured as a slurpd or syncrepl consumer -before this keyword may be set. This mode must be used with extreme -care, as it does not offer any consistency guarantees. This feature -is intended to be used with an external frontend that guarantees that -writes are only directed to a single master, switching to an alternate -server only if the original master goes down. +database must already be configured as a syncrepl consumer +before this keyword may be set. This mode also requires a +.B serverID +(see above) to be configured. By default, mirrormode is off. .TP .B overlay @@ -1359,6 +1355,8 @@ of the order in which they were configured and the database itself will receive control last of all. See the .BR slapd.overlays (5) manual page for an overview of the available overlays. +Note that all of the database's +regular settings should be configured before any overlay settings. .TP .B readonly on | off This option puts the database into "read-only" mode. Any attempts to @@ -1426,18 +1424,6 @@ If an objectClass is listed, all the related attributes are (are not) replicated. .RE .TP -.B replogfile -Specify the name of the replication log file to log changes to. -The replication log is typically written by -.BR slapd (8) -and read by -.BR slurpd (8). -See -.BR slapd.replog (5) -for more information. The specified file should be located -in a directory with limited read/write/execute access as the replication -logs may contain sensitive information. -.TP .B restrict Specify a whitespace separated list of operations that are restricted. If defined inside a database specification, restrictions apply only @@ -1600,7 +1586,8 @@ replication engine. identifies the current .B syncrepl directive within the replication consumer site. -It is a non-negative integer having no more than three digits. +It is a non-negative integer not greater than 4095 (limited +to three hexadecimal digits). .B provider specifies the replication provider site containing the master content @@ -1670,6 +1657,7 @@ and .B credentials and should only be used when adequate security services (e.g. TLS or IPSEC) are in place. +.B REMEMBER: simple bind credentials must be in cleartext! A .B bindmethod of @@ -1726,12 +1714,10 @@ ignored. .TP .B updatedn This option is only applicable in a slave -database updated using -.BR slurpd(8). +database. It specifies the DN permitted to update (subject to access controls) -the replica (typically, this is the DN -.BR slurpd (8) -binds to update the replica). Generally, this DN +the replica. It is only needed in certain push-mode +replication scenarios. Generally, this DN .I should not be the same as the .B rootdn @@ -1810,8 +1796,7 @@ default slapd configuration file .BR slapdn (8), .BR slapindex (8), .BR slappasswd (8), -.BR slaptest (8), -.BR slurpd (8). +.BR slaptest (8). .LP "OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) .SH ACKNOWLEDGEMENTS diff --git a/doc/man/man5/slapd.overlays.5 b/doc/man/man5/slapd.overlays.5 index 251f61f234..3e02d59d89 100644 --- a/doc/man/man5/slapd.overlays.5 +++ b/doc/man/man5/slapd.overlays.5 @@ -36,6 +36,17 @@ This overlay allows automatic referral chasing when a referral would have been returned, either when configured by the server or when requested by the client. .TP +.B constraint +Constraint. +This overlay enforces a regular expression constraint on all values +of specified attributes. It is used to enforce a more rigorous +syntax when the underlying attribute syntax is too general. +.TP +.B dds +Dynamic Directory Services. +This overlay supports dynamic objects, which have a limited life after +which they expire and are automatically deleted. +.TP .B dyngroup Dynamic Group. This is a demo overlay which extends the Compare operation to detect @@ -98,6 +109,11 @@ Attribute Uniqueness. This overlay can be used with a backend database such as .BR slapd-bdb (5) to enforce the uniqueness of some or all attributes within a subtree. +.TP +.B valsort +Value Sorting. +This overlay can be used to enforce a specific order for the values +of an attribute when it is returned in a search. .SH FILES .TP ETCDIR/slapd.conf @@ -110,6 +126,9 @@ default slapd configuration directory .BR slapo\-accesslog (5), .BR slapo\-auditlog (5), .BR slapo\-chain (5), +.BR slapo\-constraint (5), +.BR slapo\-dds (5), +.BR slapo\-dyngroup (5), .BR slapo\-dynlist (5), .BR slapo\-pcache (5), .BR slapo\-ppolicy (5), @@ -119,6 +138,7 @@ default slapd configuration directory .BR slapo\-syncprov (5), .BR slapo\-translucent (5), .BR slapo\-unique (5). +.BR slapo\-valsort (5). .BR slapd\-config (5), .BR slapd.conf (5), .BR slapd.backends (5), diff --git a/doc/man/man5/slapd.plugin.5 b/doc/man/man5/slapd.plugin.5 index de9e4f3abc..c25b69b646 100644 --- a/doc/man/man5/slapd.plugin.5 +++ b/doc/man/man5/slapd.plugin.5 @@ -10,9 +10,7 @@ The .BR slapd.conf (5) file contains configuration information for the .BR slapd (8) -daemon. This configuration file is also used by the -.BR slurpd (8) -replication daemon and by the SLAPD tools +daemon. This configuration file is also used by the SLAPD tools .BR slapadd (8), .BR slapcat (8), and diff --git a/doc/man/man5/slapd.replog.5 b/doc/man/man5/slapd.replog.5 deleted file mode 100644 index 87f1c7398d..0000000000 --- a/doc/man/man5/slapd.replog.5 +++ /dev/null @@ -1,167 +0,0 @@ -.TH SLAPD.REPLOG 5 "RELEASEDATE" "OpenLDAP LDVERSION" -.\" $OpenLDAP$ -.\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. -.\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.SH NAME -slapd.replog \- slapd replication log format -.SH SYNOPSIS -slapd.replog -slapd.replog.lock -.SH DESCRIPTION -.LP -The file slapd.replog is produced by the stand-alone LDAP daemon, -.BR slapd (8), -when changes are made to its local database that are to be -propagated to one or more replica -.IR slapd s. -The file consists of -zero or more records, each one corresponding to a change, addition, -or deletion from the -.I slapd -database. The file is meant to be read -and processed by -.BR slurpd (8), -the stand-alone LDAP update replication daemon. The records are -separated by a blank line. Each record has the following format. -.LP -The record begins with one or more lines indicating the replicas -to which the change is to be propagated: -.LP -.nf - replica: -.fi -.LP -Next, the time the change took place given, as the number of seconds since -00:00:00 GMT, Jan. 1, 1970, with an optional decimal extension, in order -to make times unique. Note that slapd does not make times unique, but -slurpd makes all times unique in its copies of the replog files. -.LP -.nf - time: -.fi -.LP -Next, the distinguished name of the entry being changed is given: -.LP -.nf - dn: -.fi -.LP -Next, the type of change being made is given: -.LP -.nf - changetype: <[modify|add|delete|modrdn]> -.fi -.LP -Finally, the change information itself is given, the format of which -depends on what kind of change was specified above. For a \fIchangetype\fP -of \fImodify\fP, the format is one or more of the following: -.LP -.nf - add: - : - : - ... - - -.fi -.LP -Or, for a replace modification: -.LP -.nf - replace: - : - : - ... - - -.fi -.LP -Or, for a delete modification: -.LP -.nf - delete: - : - : - ... - - -.fi -.LP -If no \fIattributetype\fP lines are given, the entire attribute is to be -deleted. -.LP -For a \fIchangetype\fP of \fIadd\fP, the format is: -.LP -.nf - : - : - ... - : - : -.fi -.LP -For a \fIchangetype\fP of \fImodrdn\fP, the format is: -.LP -.nf - newrdn: - deleteoldrdn: 0 | 1 -.fi -.LP -where a value of 1 for deleteoldrdn means to delete the values -forming the old rdn from the entry, and a value of 0 means to -leave the values as non-distinguished attributes in the entry. -.LP -For a \fIchangetype\fP of \fIdelete\fP, no additional information -is needed in the record. -.LP -The format of the values is the LDAP Directory Interchange Format -described in -.BR ldif (5). -.LP -Access to the \fIslapd.replog\fP file is synchronized through the -use of -.BR flock (3) -on the file \fIslapd.replog.lock\fP. Any process -reading or writing this file should obey this locking convention. -.SH EXAMPLE -The following sample \fIslapd.replog\fP file contains information -on one of each type of change. -.LP -.nf - replica: truelies.rs.itd.umich.edu - replica: judgmentday.rs.itd.umich.edu - time: 797612941 - dn: cn=Babs Jensen,dc=example,dc=com - changetype: add - objectclass: person - cn: babs - cn: babs jensen - sn: jensen - - replica: truelies.rs.itd.umich.edu - replica: judgmentday.rs.itd.umich.edu - time: 797612973 - dn: cn=Babs Jensen,dc=example,dc=com - changetype: modify - add: description - description: the fabulous babs - - replica: truelies.rs.itd.umich.edu - replica: judgmentday.rs.itd.umich.edu - time: 797613020 - dn: cn=Babs Jensen,dc=example,dc=com - changetype: modrdn - newrdn: cn=Barbara J Jensen - deleteoldrdn: 0 -.fi -.SH FILES -.TP -slapd.replog -slapd replication log file -.TP -slapd.replog.lock -lockfile for slapd.replog -.SH SEE ALSO -.BR ldap (3), -.BR ldif (5), -.BR slapd (8), -.BR slurpd (8) -.SH ACKNOWLEDGEMENTS -.so ../Project diff --git a/doc/man/man5/slapo-accesslog.5 b/doc/man/man5/slapo-accesslog.5 index 3c51f0115d..947b8fefdc 100644 --- a/doc/man/man5/slapo-accesslog.5 +++ b/doc/man/man5/slapo-accesslog.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-accesslog \- Access Logging overlay +slapo-accesslog \- Access Logging overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-auditlog.5 b/doc/man/man5/slapo-auditlog.5 index 63cc0cfc65..ec50acd09c 100644 --- a/doc/man/man5/slapo-auditlog.5 +++ b/doc/man/man5/slapo-auditlog.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-auditlog \- Audit Logging overlay +slapo-auditlog \- Audit Logging overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-chain.5 b/doc/man/man5/slapo-chain.5 index 3757516e0a..177db91cb2 100644 --- a/doc/man/man5/slapo-chain.5 +++ b/doc/man/man5/slapo-chain.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See the COPYRIGHT file. .\" $OpenLDAP$ .SH NAME -slapo-chain \- chain overlay +slapo-chain \- chain overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-constraint.5 b/doc/man/man5/slapo-constraint.5 new file mode 100644 index 0000000000..e5752fdb0a --- /dev/null +++ b/doc/man/man5/slapo-constraint.5 @@ -0,0 +1,57 @@ +.TH SLAPO-CONSTRAINT 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2005-2006 Hewlett-Packard Company +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +slapo-constraint \- Attribute Constraint Overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The constraint overlay is used to enforce a regular expression +constraint on all values of specified attributes. Attributes can +have multiple constraints placed upon them, and all must be satisfied +when modifying an attribute value under constraint. +.LP +This overlay is intended to be used to force syntactic regularity upon +certain string represented data which have well known canonical forms, +like telephone numbers, post codes, FQDNs, etc. +.SH CONFIGURATION +This +.B slapd.conf +option applies to the constraint overlay. +It should appear after the +.B overlay +directive. +.TP +.B constraint_attribute +Specifies the constraint which should apply to the attribute named as +the first parameter. +At the moment only one type of constraint is supported - +.B +regex. +The parameter following the +.B +regex +type is a Unix style regular expression (See +.B +regex(7)) + +Any attempt to add or modify an attribute named as part of the +constraint overlay specification which does not fit the regular +expression constraint listed will fail with a +LDAP_CONSTRAINT_VIOLATION error. +.SH EXAMPLES +.B +constraint_attribute mail regex ^[:alnum:]+@mydomain.com$ + +A specification like the above would reject any +.B +mail +attribute which did not look like +.B +@mydomain.com +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). diff --git a/doc/man/man5/slapo-dds.5 b/doc/man/man5/slapo-dds.5 index 77196ca920..6cba6cd9ed 100644 --- a/doc/man/man5/slapo-dds.5 +++ b/doc/man/man5/slapo-dds.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See the COPYRIGHT file. .\" $OpenLDAP$ .SH NAME -slapo-dds \- dds overlay +slapo-dds \- Dynamic Directory Services overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -15,12 +15,13 @@ implements dynamic objects as per RFC 2589. The name .B dds stands for -Dynamic Dyrectory Services. +Dynamic Directory Services. It allows to define dynamic objects, characterized by the .B dynamicObject objectClass. -Dynamic objects have a limited life, determined by a time-to-live (TTL) -that can be refreshed by means of a specific + +Dynamic objects have a limited lifetime, determined by a time-to-live +(TTL) that can be refreshed by means of a specific .B refresh extended operation. This operation allows to set the Client Refresh Period (CRP), @@ -28,16 +29,18 @@ namely the period between refreshes that is required to preserve the dynamic object from expiration. The expiration time is computed by adding the requested TTL to the current time. -When dynamic objects reach the end of their life without being -further refreshed, they are automatically deleted; there is no guarantee -of immediate deletion, but clients should not count over it. -Dynamic objects can have subordinates, provided they also are dynamic +When dynamic objects reach the end of their lifetime without being +further refreshed, they are automatically deleted. +There is no guarantee of immediate deletion, so clients should not count +on it. + +Dynamic objects can have subordinates, provided these also are dynamic objects. -RFC 2589 does not specify what should the behavior of a dynamic -directory service be when a dynamic object with (dynamic) subordinates +RFC 2589 does not specify what the behavior of a dynamic directory +service should be when a dynamic object with (dynamic) subordinates expires. -In this implementation, the life of dynamic objects with subordinates -is prolonged until all the dynamic subordinates expired. +In this implementation, the lifetime of dynamic objects with subordinates +is prolonged until all the dynamic subordinates expire. This @@ -61,7 +64,7 @@ and operations. Since its use may result in many internal entry lookups, adds and deletes, it should be best used in conjunction with backends -that have resonably good write performances. +that have reasonably good write performances. .LP The config directives that are specific to the @@ -73,19 +76,20 @@ database or to other stacked overlays. .TP .B dds\-max\-ttl -Specifies the max TTL value; this is the default TTL newly created +Specifies the max TTL value. +This is also the default TTL newly created dynamic objects receive, unless .B dds\-default\-ttl is set. -When the client with a refresh exop requests a TTL higher than it, -sizeLimitExceeded is returned. +When the client with a refresh extended operation requests a TTL higher +than it, sizeLimitExceeded is returned. This value must be between 86400 (1 day, the default) and 31557600 (1 year plus 6 hours, as per RFC 2589). .TP .B dds\-min\-ttl Specifies the min TTL value; clients requesting a lower TTL by means -of the refresh exop actually obtain this value as CRP. +of the refresh extended operation actually obtain this value as CRP. If set to 0 (the default), no lower limit is set. .TP @@ -103,11 +107,12 @@ Specifies the interval between expiration checks; defaults to 1 hour. .B dds\-tolerance Specifies an extra time that is added to the timer that actually wakes up the thread that will delete an expired dynamic object. -So the nominal life of the entry is that specified in the +So the nominal lifetime of the entry is that specified in the .B entryTtl -attribute, but its life will actually be -.BR " entryTtl + tolerance " . -Note that there is no guarantee that the life of a dynamic object will be +attribute, but its lifetime will actually be +.BR "entryTtl + tolerance" . +Note that there is no guarantee that the lifetime of a dynamic object +will be .I exactly the requested TTL; due to implementation details, it may be longer, which is allowed by RFC 2589. @@ -117,8 +122,8 @@ By default, tolerance is 0. .B dds\-max\-dynamicObjects Specifies the maximum number of dynamic objects that can simultaneously exist within a naming context. -This allows to limit the amount of resources (mostly in terms of runqueue size) -that are used by dynamic objects. +This allows to limit the amount of resources (mostly in terms of +run-queue size) that are used by dynamic objects. By default, no limit is set. .TP @@ -146,8 +151,8 @@ is an operational, NO-USER-MODIFICATION attribute, no direct write access to it is possible. So the .B dds -overlay turns refresh exops into an internal modification to the value -of the +overlay turns refresh extended operation into an internal modification to +the value of the .B entryTtl attribute with the .B manageDIT @@ -155,7 +160,7 @@ control set. RFC 2589 recommends that anonymous clients should not be allowed to refresh a dynamic object. -This cn be implemented by appropriately crafting access control to obtain +This can be implemented by appropriately crafting access control to obtain the desired effect. Example: restrict refresh to authenticated clients @@ -218,7 +223,7 @@ dynamic objects replicate. Only the master takes care of handling dynamic object expiration, while replicas simply see the dynamic object as a plain object. -When using slurpd replication, one needs to explicitly exclude the +When replicating these objects, one needs to explicitly exclude the .B dynamicObject class and the .B entryTtl @@ -227,21 +232,10 @@ This implementation of RFC 2589 introduces a new operational attribute, .BR entryExpireTimestamp , that contains the expiration timestamp. This must be excluded from replication as well. -In -.BR slapd.conf (5), -add the following \fIexclusion list\fP to each -.B replica -statement: - -.RS -.nf -replica ... - attrs!=@dynamicObject,entryTtl,entryExpireTimestamp -.fi -.RE -When using syncrepl, the quick and dirty solution is to set +The quick and dirty solution is to set .B schemacheck=off +in the syncrepl configuration and, optionally, exclude the operational attributes from replication, using .RS diff --git a/doc/man/man5/slapo-dyngroup.5 b/doc/man/man5/slapo-dyngroup.5 new file mode 100644 index 0000000000..77288311e2 --- /dev/null +++ b/doc/man/man5/slapo-dyngroup.5 @@ -0,0 +1,48 @@ +.TH SLAPO-DYNGROUP 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2005-2007 The OpenLDAP Foundation All Rights Reserved. +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapo-dyngroup \- Dynamic Group overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The Dynamic Group overlay allows clients to use LDAP Compare operations +to test the membership of a dynamic group the same way they would check +against a static group. Compare operations targeting a group's static +member attribute will be intercepted and tested against the configured +dynamic group's URL attribute. +.LP +Note that this intercept only happens if the actual +Compare operation does not return a LDAP_COMPARE_TRUE result. So if a +group has both static and dynamic members, the static member list will +be checked first. +.SH CONFIGURATION +This +.B slapd.conf +option applies to the Dynamic Group overlay. +It should appear after the +.B overlay +directive. +.TP +.B attrpair +Specify the attributes to be compared. A compare operation on the +.I memberAttr +will cause the +.I URLattr +to be evaluated for the result. +.SH EXAMPLES +.nf + database bdb + ... + overlay dyngroup + attrpair member memberURL +.fi +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). +.SH AUTHOR +Howard Chu diff --git a/doc/man/man5/slapo-dynlist.5 b/doc/man/man5/slapo-dynlist.5 index 4a1be57232..7ae8d92686 100644 --- a/doc/man/man5/slapo-dynlist.5 +++ b/doc/man/man5/slapo-dynlist.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See the COPYRIGHT file. .\" $OpenLDAP$ .SH NAME -slapo-dynlist \- Dynamic List overlay +slapo-dynlist \- Dynamic List overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -45,7 +45,7 @@ for details. .LP This .B slapd.conf -configuration option is define for the dynlist overlay. It may have multiple +configuration option is defined for the dynlist overlay. It may have multiple occurrences, and it must appear after the .B overlay directive. @@ -58,7 +58,7 @@ data. The value .B -is the name of the attributeDescription that cointains the URI that is +is the name of the attributeDescription that contains the URI that is expanded by the overlay; if none is present, no expansion occurs. If the intersection of the attributes requested by the search operation (or the asserted attribute for compares) and the attributes listed @@ -89,6 +89,18 @@ In case the URI expansion is very resource-intensive and occurs frequently with well-defined patterns, one should consider adding a proxycache later on in the overlay stack. +.SH AUTHORIZATION +By default the expansions are performed using the identity of the current +LDAP user. This identity may be overridden by setting the +.B dgIdentity +attribute to the DN of another LDAP user. In that case the dgIdentity +will be used when expanding the URIs in the object. Setting the dgIdentity +to a zero-length string will cause the expansions to be performed +anonymously. Note that the dgIdentity attribute is defined in the +.B dyngroup +schema, and this schema must be loaded before the dgIdentity +authorization feature may be used. + .SH EXAMPLE This example collects all the email addresses of a database into a single entry; first of all, make sure that slapd.conf contains the directives: @@ -135,6 +147,18 @@ attribute: .fi .LP +A dynamic group with dgIdentity authorization could be created with an +entry like +.LP +.nf + dn: cn=Dynamic Group,ou=Groups,dc=example,dc=com + objectClass: groupOfURLs + objectClass: dgIdentityAux + cn: Dynamic Group + memberURL: ldap:///ou=People,dc=example,dc=com??sub?(objectClass=person) + dgIdentity: cn=Group Proxy,ou=Services,dc=example,dc=com +.fi + .SH FILES .TP ETCDIR/slapd.conf diff --git a/doc/man/man5/slapo-memberof.5 b/doc/man/man5/slapo-memberof.5 new file mode 100644 index 0000000000..b9f6e06761 --- /dev/null +++ b/doc/man/man5/slapo-memberof.5 @@ -0,0 +1,114 @@ +.TH SLAPO-MEMBEROF 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2007 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo-memberof \- Reverse Group Membership overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B memberof +overlay to +.BR slapd (8) +allows automatic reverse group membership maintenance. +Any time a group entry is modified, its members are modified as appropriate +in order to keep a DN-valued "is member of" attribute updated with the DN +of the group. + +.SH CONFIGURATION +The config directives that are specific to the +.B memberof +overlay must be prefixed by +.BR memberof\- , +to avoid potential conflicts with directives specific to the underlying +database or to other stacked overlays. + +.TP +.B overlay memberof +This directive adds the memberof overlay to the current database; see +.BR slapd.conf (5) +for details. + +.LP +The following +.B slapd.conf +configuration options are defined for the memberofoverlay. + +.TP +.B memberof-group-oc +The value +.B +is the name of the objectClass that triggers the reverse group membership +update. +It defaults to \fIgroupOfNames\fP. + +.TP +.B memberof-member-ad +The value +.B +is the name of the attribute that contains the names of the members +in the group objects; it must be DN-valued. +It defaults to \fImember\fP. + +.TP +.B memberof-memberof-ad +The value +.B +is the name of the attribute that contains the names of the groups +an entry is member of; it must be DN-valued. Its contents are +automatically updated by the overlay. +It defaults to \fImemberOf\fP. + +.TP +.B memberof-dn +The value +.B +contains the DN that is used as \fImodifiersName\fP for internal +modifications performed to update the reverse group membership. +It defaults to the \fIrootdn\fP of the underlying database. + +.TP +.B memberof-dangling {ignore, drop, error} +This option determines the behavior of the overlay when, during +a modification, it encounters dangling references. +The default is +.BR ignore , +which may leave dangling references. +Other options are +.BR drop , +which discards those modifications that would result in dangling +references, and +.BR error , +which causes modifications that would result in dangling references +to fail. + +.TP +.B memberof-refint {true|FALSE} +This option determines whether the overlay will try to preserve +referential integrity or not. +If set to +.BR TRUE , +when an entry containing values of the "is member of" attribute is modified, +the corresponding groups are modified as well. + +.LP +The memberof overlay may be used with any backend that provides full +read-write functionality, but it is mainly intended for use +with local storage backends. + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5), +.BR slapd (8). +The +.BR slapo-memberof (5) +overlay supports dynamic configuration via +.BR back-config . +.SH ACKNOWLEDGEMENTS +.P +This module was written in 2005 by Pierangelo Masarati for SysNet s.n.c. + diff --git a/doc/man/man5/slapo-pcache.5 b/doc/man/man5/slapo-pcache.5 index f20270945e..032f325067 100644 --- a/doc/man/man5/slapo-pcache.5 +++ b/doc/man/man5/slapo-pcache.5 @@ -4,7 +4,7 @@ .\" Copyright 2001, Pierangelo Masarati, All rights reserved. .\" $OpenLDAP$ .SH NAME -slapo-pcache \- proxycache overlay +slapo-pcache \- proxycache overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -67,15 +67,39 @@ returned is less than . Consistency check is performed every .RS proxycache \fBbdb 10000 1 50 100\fP .RE + .TP .B proxycachequeries Specify the maximum number of queries to cache. The default is 10000. +.TP +.B proxysavequeries { TRUE | FALSE } +Specify whether the cached queries should be saved across restarts +of the caching proxy, to provide hot startup of the cache. Only non-expired +queries are reloaded. The default is FALSE. + +.BR CAVEAT : +of course, the configuration of the proxycache must not change +across restarts; the pcache overlay does not perform any consistency +checks in this sense. +In detail, this option should be disabled unless the existing +.B proxyattrset +and +.B proxytemplate +directives are not changed neither in order nor in contents. +If new sets and templates are added, or if other details of the pcache +overlay configuration changed, this feature should not be affected. + .TP .B proxyattrset Used to associate a set of attributes with an . Each attribute set is associated with an integer from 0 to -1. These indices are used by the \fBproxytemplate\fP directive to define cacheable templates. +A set of attributes cannot be empty. A set of attributes can contain the +special attributes "*" (all user attributes), "+" (all operational attributes) +or both; in the latter case, any other attribute is redundant and should +be avoided for clarity. A set of attributes can contain "1.1" as the only +attribute; in this case, only the presence of the entries is cached. .TP .B proxytemplate [] diff --git a/doc/man/man5/slapo-ppolicy.5 b/doc/man/man5/slapo-ppolicy.5 index 5a507e176b..95335dcfad 100644 --- a/doc/man/man5/slapo-ppolicy.5 +++ b/doc/man/man5/slapo-ppolicy.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .TH SLAPO_PPOLICY 5 "RELEASEDATE" "OpenLDAP LDVERSION" .SH NAME -slapo-ppolicy \- Password Policy overlay +slapo-ppolicy \- Password Policy overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -565,7 +565,7 @@ This attribute contains the time that the user's account was locked. If the account has been locked, the password may no longer be used to authenticate the user to the directory. If .B pwdAccountLockedTime -is set to zero (0), the user's account has been permanently locked +is set to 000001010000Z, the user's account has been permanently locked and may only be unlocked by an administrator. .LP .RS 4 diff --git a/doc/man/man5/slapo-refint.5 b/doc/man/man5/slapo-refint.5 index 1881b8de90..5d4ae93828 100644 --- a/doc/man/man5/slapo-refint.5 +++ b/doc/man/man5/slapo-refint.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-refint \- Referential Integrity overlay +slapo-refint \- Referential Integrity overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-retcode.5 b/doc/man/man5/slapo-retcode.5 index 313dd228eb..9b1b4bb338 100644 --- a/doc/man/man5/slapo-retcode.5 +++ b/doc/man/man5/slapo-retcode.5 @@ -4,7 +4,7 @@ .\" Copyright 2001, Pierangelo Masarati, All rights reserved. .\" $OpenLDAP$ .SH NAME -slapo-retcode \- return code overlay +slapo-retcode \- return code overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-rwm.5 b/doc/man/man5/slapo-rwm.5 index 9ab1c1b3b7..dddf0a7deb 100644 --- a/doc/man/man5/slapo-rwm.5 +++ b/doc/man/man5/slapo-rwm.5 @@ -8,7 +8,7 @@ .\" and maybe manual pages for librewrite. .\" .SH NAME -slapo-rwm \- rewrite/remap overlay +slapo-rwm \- rewrite/remap overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -71,6 +71,24 @@ defined as using the distinguishedName syntax. Also, note that there are DN-related syntaxes (i.e. compound types with a portion that is DN-valued), like nameAndOptionalUID, whose values are currently not rewritten. +.LP +If the foreign type of an attribute mapping is not defined on the local +server, it might be desirable to have the attribute values normalized after +the mapping process. Not normalizing the values can lead to wrong results, +when the +.B rwm +overlay is used together with e.g. the +.B pcache +overlay. This normalization can be enabled by means of the +.B rwm-normalize-mapped-attrs +directive. +.TP +.B rwm-normalize-mapped-attrs {yes|no} +Set this to "yes", if the +.B rwm +overlay should try to normalize the values of attributes that are mapped from +an attribute type that is unknown to the local server. The default value of +this setting is "no". .SH SUFFIX MASSAGING A basic feature of the .B rwm @@ -78,6 +96,20 @@ overlay is the capability to perform suffix massaging between a virtual and a real naming context by means of the .B rwm-suffixmassage directive. +This, in conjunction with proxy backends, +.BR slapd-ldap (5) +and +.BR slapd-meta (5), +or with the relay backend, +.BR slapd-relay (5), +allows to create virtual views of databases. +A distinguishing feature of this overlay is that, when instantiated +before any database, it can modify the DN of requests +.I before +database selection. +For this reason, rules that rewrite the empty DN ("") +or the subschemaSubentry DN (usually "cn=subschema"), +would prevent clients from reading the root DSE or the DSA's schema. .TP .B rwm-suffixmassage "[]" "" Shortcut to implement naming context rewriting; the trailing part diff --git a/doc/man/man5/slapo-syncprov.5 b/doc/man/man5/slapo-syncprov.5 index 1b3059c3eb..c6bc84bac1 100644 --- a/doc/man/man5/slapo-syncprov.5 +++ b/doc/man/man5/slapo-syncprov.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-syncprov \- Sync Provider overlay +slapo-syncprov \- Sync Provider overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION @@ -21,9 +21,6 @@ memory on startup, and maintained in memory thereafter. Checkpoints may be configured to write the contextCSN into the underlying database to minimize recovery time after an unclean shutdown. -Note that due to deadlock constraints in the LDBM database, this overlay -will only work in RefreshOnly mode, and cannot perform checkpoints, on LDBM. - On databases that support inequality indexing, it is helpful to set an eq index on the entryCSN attribute when using this overlay. .SH CONFIGURATION diff --git a/doc/man/man5/slapo-translucent.5 b/doc/man/man5/slapo-translucent.5 index 3afec26d72..f33c14c98e 100644 --- a/doc/man/man5/slapo-translucent.5 +++ b/doc/man/man5/slapo-translucent.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-translucent \- Translucent Proxy overlay +slapo-translucent \- Translucent Proxy overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man5/slapo-unique.5 b/doc/man/man5/slapo-unique.5 index e25df84918..b5de5e8844 100644 --- a/doc/man/man5/slapo-unique.5 +++ b/doc/man/man5/slapo-unique.5 @@ -3,15 +3,15 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-unique \- Attribute Uniqueness overlay +slapo-unique \- Attribute Uniqueness overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION The Attribute Uniqueness overlay can be used with a backend database such as .BR slapd-bdb (5) -to enforce the uniqueness of some or all attributes within a subtree. This -subtree defaults to the base DN of the database for which the Uniqueness -overlay is configured. +to enforce the uniqueness of some or all attributes within a +scope. This subtree defaults to all objects within the subtree of the +database for which the Uniqueness overlay is configured. .LP Uniqueness is enforced by searching the subtree to ensure that the values of all attributes presented with an @@ -19,7 +19,7 @@ all attributes presented with an .B modify or .B modrdn -operation are unique within the subtree. +operation are unique within the scope. For example, if uniqueness were enforced for the .B uid attribute, the subtree would be searched for any other records which also @@ -35,18 +35,59 @@ They should appear after the .B overlay directive. .TP -.B unique_base -Configure the subtree against which uniqueness searches will be invoked. +.B unique_uri <[strict ][ignore ]URI[URI...]...> +Configure the base, attributes, scope, and filter for uniqueness +checking. Multiple URIs may be specified within a domain, allowing complex selections of objects. Multiple +.B unique_uri +statements or +.B olcUniqueURI +attributes will create independent domains, each with their own independent lists of URIs and ignore/strict settings. + +The LDAP URI syntax is a subset of +.B RFC-4516, +and takes the form: + +ldap:///[base dn]?[attributes...]?scope[?filter] + The -.B basedn -defaults to the base DN of the database for which uniqueness is configured. -.TP -.B unique_ignore -Configure one or more attributes for which uniqueness will not be enforced. -If not configured, all non-operational (eg, system) attributes must be +.B base dn +defaults to that of the back-end database. Specified base dns must be within the subtree of the back-end database. + +If no +.B attributes +are specified, the URI applies to all non-operational attributes. + +The +.B scope +component is effectively mandatory, because LDAP URIs default to +.B base +scope, which is not valid for uniqueness, because groups of one object +are always unique. Scopes of +.B sub +(for subtree) and +.B one +for one-level are valid. + +The +.B filter +component causes the domain to apply uniqueness constraints only to +matching objects. e.g. +.B ldap:///?cn?sub?(sn=e*) +would require unique +.B cn +attributes for all objects in the subtree of the back-end database whose +.B sn +starts with an e. + +It is possible to assert uniqueness upon all non-operational +attributes except those listed by prepending the keyword +.B ignore +If not configured, all non-operational (e.g., system) attributes must be unique. Note that the -.B unique_ignore -list should generally contain the +.B attributes +list of an +.B ignore +URI should generally contain the .BR objectClass , .BR dc , .B ou @@ -54,42 +95,55 @@ and .B o attributes, as these will generally not be unique, nor are they operational attributes. + +It is possible to set strict checking for the uniqueness domain by +prepending the keyword +.B strict. +By default, uniqueness is not enforced +for null values. Enabling +.B strict +mode extends the concept of uniqueness to include null values, such +that only one attribute within a subtree will be allowed to have a +null value. Strictness applies to all URIs within a uniqueness +domain, but some domains may be strict while others are not. +.LP +It is not possible to set both URIs and legacy slapo-unique configuration parameters simultaneously. In general, the legacy configuration options control pieces of a single unfiltered subtree domain. +.TP +.B unique_base +This legacy configuration parameter should be converted to the +.B base dn +component of the above +.B unique_uri +style of parameter. +.TP +.B unique_ignore +This legacy configuration parameter should be converted to a +.B unique_uri +parameter with +.B ignore +keyword as described above. .TP .B unique_attributes -Specify one or more attributes for which uniqueness will be enforced. -If not specified, all attributes which are not operational (eg, system -attributes such as -.B entryUUID ) -or specified via the -.B unique_ignore -directive above must be unique within the subtree. +This legacy configuration parameter should be converted to a +.B unique_uri +parameter, as described above. .TP .B unique_strict -By default, uniqueness is not enforced for null values. Enabling -.B unique_strict -mode extends the concept of uniqueness to include null values, such that -only one attribute within a subtree will be allowed to have a null value. +This legacy configuration parameter should be converted to a +.B strict +keyword prepended to a +.B unique_uri +parameter, as described above. .SH CAVEATS .LP -The search key is generated with attributes that are non-operational, not -on the -.B unique_ignore -list, and included in the -.B unique_attributes -list, in that order. This makes it possible to create interesting and -unusable configurations. Usually only one of -.B unique_ignore -or -.B unique_attributes -should be configured; use -.B unique_ignore -if the majority of attributes should be unique, and use -.B unique_attributes -if only a small set of attributes should be unique. +.B unique_uri +cannot be used with the old-style of configuration, and vice versa. +.B unique_uri +can implement everything the older system can do, however. .LP Typical attributes for the -.B unique_ignore -directive are intentionally not hardcoded into the overlay to allow for +.B ignore ldap:///... +URIs are intentionally not hardcoded into the overlay to allow for maximum flexibility in meeting site-specific requirements. .SH FILES .TP diff --git a/doc/man/man5/slapo-valsort.5 b/doc/man/man5/slapo-valsort.5 index 3b483bb9c4..453b8c9afc 100644 --- a/doc/man/man5/slapo-valsort.5 +++ b/doc/man/man5/slapo-valsort.5 @@ -3,7 +3,7 @@ .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .\" $OpenLDAP$ .SH NAME -slapo-valsort \- Value Sorting overlay +slapo-valsort \- Value Sorting overlay to slapd .SH SYNOPSIS ETCDIR/slapd.conf .SH DESCRIPTION diff --git a/doc/man/man8/slapadd.8 b/doc/man/man8/slapadd.8 index deaea25665..7cecd3d527 100644 --- a/doc/man/man8/slapadd.8 +++ b/doc/man/man8/slapadd.8 @@ -8,15 +8,17 @@ slapadd \- Add entries to a SLAPD database .B SBINDIR/slapadd .B [\-b suffix] .B [\-c] -.B [\-g] .B [\-d level] .B [\-f slapd.conf] .B [\-F confdir] +.B [\-g] .B [\-j lineno] .B [\-l ldif-file] .B [\-n dbnum] .B [\-o name[=value] .B [\-q] +.B [\-s] +.B [\-S SID] .B [\-u] .B [\-v] .B [\-w] @@ -118,6 +120,10 @@ databases containing special objects, such as fractional objects on a partial replica. Loading normal objects which do not conform to schema may result in unexpected and ill behavior. .TP +.B \-S " SID" +Server ID to use in generated entryCSN. Also used for contextCSN +if `\-w' is set as well. Defaults to 0. +.TP .B \-u enable dry-run (don't write to backend) mode. .TP diff --git a/doc/man/man8/slapauth.8 b/doc/man/man8/slapauth.8 index 8420184504..14a4a033a5 100644 --- a/doc/man/man8/slapauth.8 +++ b/doc/man/man8/slapauth.8 @@ -2,7 +2,7 @@ .\" Copyright 2004-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -slapauth \- Check a list of string-represented IDs for authc/authz. +slapauth \- Check a list of string-represented IDs for LDAP authc/authz .SH SYNOPSIS .B SBINDIR/slapauth .B [\-d level] diff --git a/doc/man/man8/slapcat.8 b/doc/man/man8/slapcat.8 index 498d148125..f591a658fa 100644 --- a/doc/man/man8/slapcat.8 +++ b/doc/man/man8/slapcat.8 @@ -134,10 +134,18 @@ option is given. .B \-v Enable verbose mode. .SH LIMITATIONS -In general, your +For some backend types, your .BR slapd (8) should not be running (at least, not in read-write -mode) when you do this to ensure consistency of the database. +mode) when you do this to ensure consistency of the database. It is +always safe to run +.B slapcat +with the +.BR slapd-bdb (5), +.BR slapd-hdb (5), +and +.BR slapd-null (5) +backends. .SH EXAMPLES To make a text backup of your SLAPD database and put it in a file called .BR ldif , diff --git a/doc/man/man8/slapd.8 b/doc/man/man8/slapd.8 index bb070483e1..0fd19df9f8 100644 --- a/doc/man/man8/slapd.8 +++ b/doc/man/man8/slapd.8 @@ -46,15 +46,6 @@ flag is given, even with a zero argument, .B slapd will not fork and disassociate from the invoking tty. .LP -.B Slapd -can be configured to provide replicated service for a database with -the help of -.BR slurpd , -the standalone LDAP update replication daemon. -See -.BR slurpd (8) -for details. -.LP See the "OpenLDAP Administrator's Guide" for more details on .BR slapd . .SH OPTIONS @@ -262,7 +253,7 @@ registers at SLP DAs with the three SLP attributes tree, server-type and server- that have the values given above. This allows to specifically query the SLP DAs for LDAP servers holding the .I production -tree in case multiple trees are availabe. +tree in case multiple trees are available. .RE .SH EXAMPLES To start @@ -306,8 +297,7 @@ To test whether the configuration file is correct or not, type: .BR slapdn (8), .BR slapindex (8), .BR slappasswd (8), -.BR slaptest (8), -.BR slurpd (8) +.BR slaptest (8). .LP "OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) .SH BUGS diff --git a/doc/man/man8/slapdn.8 b/doc/man/man8/slapdn.8 index 4455dc960b..e07fac1206 100644 --- a/doc/man/man8/slapdn.8 +++ b/doc/man/man8/slapdn.8 @@ -2,7 +2,7 @@ .\" Copyright 2004-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -slapdn \- Check a list of string-represented DNs based on schema syntax. +slapdn \- Check a list of string-represented LDAP DNs based on schema syntax .SH SYNOPSIS .B SBINDIR/slapdn .B [\-d level] diff --git a/doc/man/man8/slaptest.8 b/doc/man/man8/slaptest.8 index a9a66c6241..809669787f 100644 --- a/doc/man/man8/slaptest.8 +++ b/doc/man/man8/slaptest.8 @@ -2,13 +2,14 @@ .\" Copyright 2004-2007 The OpenLDAP Foundation All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME -slaptest \- Check the suitability of the slapd.conf file. +slaptest \- Check the suitability of the OpenLDAP slapd.conf file .SH SYNOPSIS .B SBINDIR/slaptest .B [\-d level] .B [\-f slapd.conf] .B [\-F confdir] .B [\-o name[=value] +.B [\-Q] .B [\-u] .B [\-v] .LP @@ -65,11 +66,15 @@ Possible generic options/values are: .fi .TP -.B \-u +.BI \-Q +Be extremely quiet: only the exit code indicates success (0) or not +(any other value). +.TP +.BI \-u enable dryrun mode (i.e. don't fail if databases cannot be opened, but config is fine). .TP -.B \-v +.BI \-v enable verbose mode. .SH EXAMPLES To check a diff --git a/doc/man/man8/slurpd.8 b/doc/man/man8/slurpd.8 deleted file mode 100644 index 0f7a303c6f..0000000000 --- a/doc/man/man8/slurpd.8 +++ /dev/null @@ -1,160 +0,0 @@ -.TH SLURPD 8C "RELEASEDATE" "OpenLDAP LDVERSION" -.\" $OpenLDAP$ -.\" Copyright 1998-2007 The OpenLDAP Foundation All Rights Reserved. -.\" Copying restrictions apply. See COPYRIGHT/LICENSE. -.SH NAME -slurpd \- Standalone LDAP Update Replication Daemon -.SH SYNOPSIS -.B LIBEXECDIR/slurpd [\-d debug\-level] -.B [\-f slapd\-config\-file] [\-r slapd\-replog\-file] -.B [\-t temp\-dir] [\-o] -.B -.SH DESCRIPTION -.LP -.B Slurpd -is used to propagate changes from one slapd database to another. If -slapd is configured to produce a replication log, -.B slurpd -reads that -replication log and sends the changes to the slave -.B slapd -instances -via the LDAP protocol. -.B slurpd -is typically invoked at boot time, usually out of -.BR /etc/rc.local . -.LP -Upon startup, -.B slurpd -normally forks and disassociates itself from the invoking tty, -then reads the replication log (given either by the -.I replogfile -directive in the -.B slapd -config file, or by the -.RB \- r -command-line option). -If the replication log file does not exist or is empty, -.B slurpd -goes to sleep. It periodically wakes up and checks to see if there -are any changes to be propagated. -.LP -When -.B slurpd -notices that there are changes to propagate to slave -.B slapd -instances, it locks the replication log, makes its own private copy, -releases the lock, and forks one copy of itself for each replica -.B slapd -to be updated. Each child process binds to the slave -.B slapd -as the -DN given by the -.I binddn -option to the -.I replica -directive in the -.B slapd -config file, and sends the changes. -.LP -See -.BR slapd (8) -for details on the standalone LDAP daemon. -.LP -Note that slurpd reads -.B replication -directive from -.BR slapd.conf (5), -but uses -.BR ldap.conf (5) -to obtain other configuration settings (such as TLS settings). -.SH OPTIONS -.TP -.BI \-d " debug\-level" -Turn on debugging as defined by -.I debug\-level. -If this option is specified, even with a zero argument, -.B slurpd -will not fork or disassociate from the invoking terminal. Some general -operation and status messages are printed for any value of \fIdebug\-level\fP. -\fIdebug\-level\fP is taken as a bit string, with each bit corresponding to a -different kind of debugging information. See for details. -.TP -.BI \-f " slapd\-config\-file" -Specifies the slapd configuration file. The default is -.BR ETCDIR/slapd.conf . -.TP -.BI \-r " slapd\-replog\-file" -Specifies the name of the -.B slapd -replication logfile. Normally, the name -of the replication log file is read from the -.B slapd -configuration file. The file should be located in a directory -with limited read/write/execute access. -The -.B \-r -option allows you to override this. In conjunction with the -.B \-o -option, you can process a replication log file in a "one\-shot" mode. For -example, if -.B slurpd -has encountered errors in processing a replication log, -you can run it in one\-shot mode and give the rejection file name as -the argument to the \-r option, once you've resolved the problem which caused -the replication to fail. -.TP -.B \-o -Run in "one\-shot" mode. Normally, -.B slurpd -processes the replog file -and then watches for more replication entries to be appended. In -one\-shot mode, -.B slurpd -processes a replication log and exits. -.TP -.BI \-t " temp\-dir" -.B slurpd -copies the replication log to a working directory before processing it. -The directory permissions should limit read/write/execute access as -temporary files may contain sensitive information. -This option allows you to specify the location of these temporary files. -The default is -.BR LOCALSTATEDIR/openldap-slurp . -.SH EXAMPLES -To start -.I slurpd -and have it fork and detach from the terminal and process -the replication logs generated by -.I slapd, -just type: -.LP -.nf -.ft tt - LIBEXECDIR/slurpd -.ft -.fi -.LP -To start -.I slurpd -with an alternate -.I slapd -configuration file, and turn -on voluminous debugging which will be printed on standard error, type: -.LP -.nf -.ft tt - LIBEXECDIR/slurpd -f ETCDIR/slapd.conf -d 255 -.ft -.fi -.LP -.SH "SEE ALSO" -.BR ldap (3), -.BR ldap.conf (5), -.BR slapd.conf (5), -.BR slapd.replog (5), -.BR slapd (8) -.LP -"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/) -.SH ACKNOWLEDGEMENTS -.so ../Project diff --git a/doc/rfc/INDEX b/doc/rfc/INDEX index 4420833bff..3908e3265d 100644 --- a/doc/rfc/INDEX +++ b/doc/rfc/INDEX @@ -64,6 +64,7 @@ rfc4530.txt LDAP: entryUUID (PS) rfc4531.txt LDAP Turn Operation (E) rfc4532.txt LDAP Who am I? Operation (PS) rfc4533.txt LDAP Content Sync Operation (E) +rfc5020.txt LDAP 'entryDN' operational attribute (PS) Legend: STD Standard diff --git a/doc/rfc/rfc5020.txt b/doc/rfc/rfc5020.txt new file mode 100644 index 0000000000..e289f8b337 --- /dev/null +++ b/doc/rfc/rfc5020.txt @@ -0,0 +1,283 @@ + + + + + + +Network Working Group K. Zeilenga +Request for Comments: 5020 Isode Limited +Category: Standards Track August 2007 + + + The Lightweight Directory Access Protocol (LDAP) entryDN + Operational Attribute + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + +Abstract + + This document describes the Lightweight Directory Access Protocol + (LDAP) / X.500 'entryDN' operational attribute. The attribute + provides a copy of the entry's distinguished name for use in + attribute value assertions. + + + + + + + + + + + + + + + + + + + + + + + + + +Zeilenga Standards Track [Page 1] + +RFC 5020 LDAP entryDN August 2007 + + +1. Background and Intended Use + + In X.500 Directory Services [X.501], such as those accessible using + the Lightweight Directory Access Protocol (LDAP) [RFC4510], an entry + is identified by its distinguished name (DN) [RFC4512]. However, as + an entry's DN is not an attribute of the entry, it is not possible to + perform attribute value assertions [RFC4511] against it. + + This document describes the 'entryDN' operational attribute which + holds a copy of the entry's distinguished name. This attribute may + be used in search filters. For instance, searching the subtree + with the filter: + + (entryDN:componentFilterMatch:=or:{ + item:{ component "3", rule rdnMatch, value "ou=A" }, + item:{ component "3", rule rdnMatch, value "ou=B" } }) + + would return entries in the subtree and + entries in subtree , but would not return any + other entries in the subtree . + + In the above paragraph, DNs are presented using the string + representation defined in [RFC4514], and the example search filter is + presented using the string representation defined in [RFC4515] with + whitespace (line breaks and indentation) added to improve + readability. The 'componentFilterMatch' and 'rdnMatch' rules are + specified in [RFC3687]. + + Schema definitions are provided using LDAP description formats + [RFC4512]. Definitions provided here are formatted (line wrapped) + for readability. + +2. 'entryDN' Operational Attribute + + The 'entryDN' operational attribute provides a copy of the entry's + current DN. + + The following is an LDAP attribute type description suitable for + publication in subschema subentries. + + ( 1.3.6.1.1.20 NAME 'entryDN' + DESC 'DN of the entry' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 + SINGLE-VALUE + NO-USER-MODIFICATION + USAGE directoryOperation ) + + + + +Zeilenga Standards Track [Page 2] + +RFC 5020 LDAP entryDN August 2007 + + + Note that the DN of the entry cannot be modified through this + attribute. + +3. Security Considerations + + As this attribute only provides an additional mechanism to access an + entry's DN, the introduction of this attribute is not believed to + introduce new security considerations. + +4. IANA Considerations + +4.1. Object Identifier Registration + + IANA has registered (upon Standards Action) an LDAP Object Identifier + [RFC4520] for use in this document. + + Subject: Request for LDAP OID Registration + Person & email address to contact for further information: + Kurt Zeilenga + Specification: RFC 5020 + Author/Change Controller: IESG + Comments: + Identifies the 'entryDN' attribute type + +4.2. 'entryDN' Descriptor Registration + + IANA has registered (upon Standards Action) the LDAP 'entryDN' + descriptor [RFC4520]. + + Subject: Request for LDAP Descriptor Registration + Descriptor (short name): entryDN + Object Identifier: 1.3.6.1.1.20 + Person & email address to contact for further information: + Kurt Zeilenga + Usage: Attribute Type + Specification: RFC 5020 + Author/Change Controller: IESG + + + + + + + + + + + + + + +Zeilenga Standards Track [Page 3] + +RFC 5020 LDAP entryDN August 2007 + + +5. References + +5.1. Normative References + + [RFC4510] Zeilenga, K., Ed., "Lightweight Directory Access Protocol + (LDAP): Technical Specification Road Map", RFC 4510, June + 2006. + + [RFC4512] Zeilenga, K., Ed., "Lightweight Directory Access Protocol + (LDAP): Directory Information Models", RFC 4512, June + 2006. + + [X.501] International Telecommunication Union - Telecommunication + Standardization Sector, "The Directory -- Models," + X.501(1993) (also ISO/IEC 9594-2:1994). + +5.2. Informative References + + [RFC3687] Legg, S., "Lightweight Directory Access Protocol (LDAP) + and X.500 Component Matching Rules", RFC 3687, February + 2004. + + [RFC4511] Sermersheim, J., Ed., "Lightweight Directory Access + Protocol (LDAP): The Protocol", RFC 4511, June 2006. + + [RFC4514] Zeilenga, K., Ed., "Lightweight Directory Access Protocol + (LDAP): String Representation of Distinguished Names", + RFC 4514, June 2006. + + [RFC4515] Smith, M., Ed., and T. Howes, "Lightweight Directory + Access Protocol (LDAP): String Representation of Search + Filters", RFC 4515, June 2006. + + [RFC4520] Zeilenga, K., "Internet Assigned Numbers Authority (IANA) + Considerations for the Lightweight Directory Access + Protocol (LDAP)", BCP 64, RFC 4520, June 2006. + +Author's Address + + Kurt D. Zeilenga + Isode Limited + + EMail: Kurt.Zeilenga@Isode.COM + + + + + + + + +Zeilenga Standards Track [Page 4] + +RFC 5020 LDAP entryDN August 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Zeilenga Standards Track [Page 5] + diff --git a/include/Makefile.in b/include/Makefile.in index cd25dca8ab..794769baf2 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -50,6 +50,8 @@ ldap_config.h: $(LDAP_CONFIG) Makefile $(SED) -e 's/\\\\/\\\\\\\\\\\\\\\\/g'`; \ libexecdir=`cygpath -w $(libexecdir) | \ $(SED) -e 's/\\\\/\\\\\\\\\\\\\\\\/g'`; \ + moduledir=`cygpath -w $(moduledir) | \ + $(SED) -e 's/\\\\/\\\\\\\\\\\\\\\\/g'`; \ localstatedir=`cygpath -w $(localstatedir) | \ $(SED) -e 's/\\\\/\\\\\\\\\\\\\\\\/g'`; \ else \ @@ -58,6 +60,7 @@ ldap_config.h: $(LDAP_CONFIG) Makefile bindir=$(bindir); \ sbindir=$(sbindir); \ libexecdir=$(libexecdir); \ + moduledir=$(moduledir); \ localstatedir=$(localstatedir); \ localedir=$(localedir); \ fi; \ @@ -67,6 +70,7 @@ ldap_config.h: $(LDAP_CONFIG) Makefile -e "s;%BINDIR%;$$bindir;" \ -e "s;%SBINDIR%;$$sbindir;" \ -e "s;%LIBEXECDIR%;$$libexecdir;" \ + -e "s;%MODULEDIR%;$$moduledir;" \ -e "s;%RUNDIR%;$$localstatedir;" \ -e "s;%LOCALEDIR%;$$localedir;" \ $(LDAP_CONFIG) >> $@; \ diff --git a/include/ac/alloca.h b/include/ac/alloca.h index 20884dd9bc..be352ccdd6 100644 --- a/include/ac/alloca.h +++ b/include/ac/alloca.h @@ -26,7 +26,7 @@ #ifdef __GNUC__ # define alloca __builtin_alloca #else -# if HAVE_ALLOCA_H +# ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX diff --git a/include/ac/crypt.h b/include/ac/crypt.h index 4596a06cbe..c5a16bd1fb 100644 --- a/include/ac/crypt.h +++ b/include/ac/crypt.h @@ -20,7 +20,7 @@ #include /* crypt() may be defined in a separate include file */ -#if HAVE_CRYPT_H +#ifdef HAVE_CRYPT_H # include #else extern char *(crypt)(); diff --git a/include/ac/dirent.h b/include/ac/dirent.h index 169d29d502..6b4de339b5 100644 --- a/include/ac/dirent.h +++ b/include/ac/dirent.h @@ -17,7 +17,7 @@ #ifndef _AC_DIRENT_H #define _AC_DIRENT_H -#if HAVE_DIRENT_H +#ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #elif defined(_MSC_VER) @@ -37,13 +37,13 @@ typedef struct DIR { #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H +# ifdef HAVE_SYS_NDIR_H # include # endif -# if HAVE_SYS_DIR_H +# ifdef HAVE_SYS_DIR_H # include # endif -# if HAVE_NDIR_H +# ifdef HAVE_NDIR_H # include # endif #endif diff --git a/include/ac/errno.h b/include/ac/errno.h index 89ef242ef7..601f2456ba 100644 --- a/include/ac/errno.h +++ b/include/ac/errno.h @@ -27,7 +27,7 @@ /* no sys_errlist */ # define sys_nerr 0 # define sys_errlist ((char **)0) -#elif DECL_SYS_ERRLIST +#elif defined( DECL_SYS_ERRLIST ) /* have sys_errlist but need declaration */ LDAP_LIBC_V(int) sys_nerr; LDAP_LIBC_V(char) *sys_errlist[]; diff --git a/include/ac/socket.h b/include/ac/socket.h index 0496c4d62c..d5644b3dfa 100644 --- a/include/ac/socket.h +++ b/include/ac/socket.h @@ -127,7 +127,7 @@ LBER_F( char * ) ber_pvt_wsa_err2string LDAP_P((int)); # define tcp_write( s, buf, len ) netwrite( s, buf, len ) # endif /* NCSA */ -#elif HAVE_CLOSESOCKET +#elif defined(HAVE_CLOSESOCKET) # define tcp_close( s ) closesocket( s ) # ifdef __BEOS__ @@ -213,8 +213,24 @@ LDAP_F (int) ldap_pvt_inet_aton LDAP_P(( const char *, struct in_addr * )); # endif #endif -#ifndef HAVE_GETPEEREID -LDAP_LUTIL_F( int ) getpeereid( int s, uid_t *, gid_t * ); +#if defined(LDAP_PF_LOCAL) && \ + !defined(HAVE_GETPEEREID) && \ + !defined(HAVE_GETPEERUCRED) && \ + !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ + defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ + defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) +# define LDAP_PF_LOCAL_SENDMSG 1 +#endif + +#ifdef HAVE_GETPEEREID +#define LUTIL_GETPEEREID( s, uid, gid, bv ) getpeereid( s, uid, gid ) +#elif defined(LDAP_PF_LOCAL_SENDMSG) +struct berval; +LDAP_LUTIL_F( int ) lutil_getpeereid( int s, uid_t *, gid_t *, struct berval *bv ); +#define LUTIL_GETPEEREID( s, uid, gid, bv ) lutil_getpeereid( s, uid, gid, bv ) +#else +LDAP_LUTIL_F( int ) lutil_getpeereid( int s, uid_t *, gid_t * ); +#define LUTIL_GETPEEREID( s, uid, gid, bv ) lutil_getpeereid( s, uid, gid ) #endif /* DNS RFC defines max host name as 255. New systems seem to use 1024 */ diff --git a/include/ac/termios.h b/include/ac/termios.h index 51f4c34ef7..ff521a63e6 100644 --- a/include/ac/termios.h +++ b/include/ac/termios.h @@ -17,7 +17,7 @@ #ifndef _AC_TERMIOS_H #define _AC_TERMIOS_H -#ifdef HAVE_POSIX_TERMIOS +#ifdef HAVE_TERMIOS_H #include #ifdef GCWINSZ_IN_SYS_IOCTL diff --git a/include/ac/time.h b/include/ac/time.h index 6dd5b541dc..cdf8cebb5a 100644 --- a/include/ac/time.h +++ b/include/ac/time.h @@ -17,10 +17,10 @@ #ifndef _AC_TIME_H #define _AC_TIME_H -#if TIME_WITH_SYS_TIME +#ifdef TIME_WITH_SYS_TIME # include # include -#elif HAVE_SYS_TIME_H +#elif defined(HAVE_SYS_TIME_H) # include # ifdef HAVE_SYS_TIMEB_H # include diff --git a/include/ac/unistd.h b/include/ac/unistd.h index dd3c2788ae..c3accf6253 100644 --- a/include/ac/unistd.h +++ b/include/ac/unistd.h @@ -17,15 +17,15 @@ #ifndef _AC_UNISTD_H #define _AC_UNISTD_H -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H # include #endif -#if HAVE_UNISTD_H +#ifdef HAVE_UNISTD_H # include #endif -#if HAVE_PROCESS_H +#ifdef HAVE_PROCESS_H # include #endif @@ -45,7 +45,7 @@ LDAP_LUTIL_F(char*)(lutil_getpass) LDAP_P((const char *getpass)); #endif /* getopt() defines may be in separate include file */ -#if HAVE_GETOPT_H +#ifdef HAVE_GETOPT_H # include #elif !defined(HAVE_GETOPT) diff --git a/include/ac/wait.h b/include/ac/wait.h index 705a2de41f..555e859bb0 100644 --- a/include/ac/wait.h +++ b/include/ac/wait.h @@ -19,7 +19,7 @@ #include -#if HAVE_SYS_WAIT_H +#ifdef HAVE_SYS_WAIT_H # include #endif diff --git a/include/lber.h b/include/lber.h index 5fb2c8a9ee..4b3a8d5ecd 100644 --- a/include/lber.h +++ b/include/lber.h @@ -138,8 +138,12 @@ typedef struct lber_memory_fns { #define LBER_SB_OPT_NEEDS_WRITE 12 #define LBER_SB_OPT_GET_MAX_INCOMING 13 #define LBER_SB_OPT_SET_MAX_INCOMING 14 + +/* Only meaningful ifdef LDAP_PF_LOCAL_SENDMSG */ +#define LBER_SB_OPT_UNGET_BUF 15 + /* Largest option used by the library */ -#define LBER_SB_OPT_OPT_MAX 14 +#define LBER_SB_OPT_OPT_MAX 15 /* LBER IO operations stacking levels */ #define LBER_SBIOD_LEVEL_PROVIDER 10 @@ -267,11 +271,14 @@ ber_get_stringb LDAP_P(( char *buf, ber_len_t *len )); +#define LBER_BV_ALLOC 0x01 /* allocate/copy result, otherwise in-place */ +#define LBER_BV_NOTERM 0x02 /* omit NUL-terminator if parsing in-place */ + LBER_F( ber_tag_t ) ber_get_stringbv LDAP_P(( BerElement *ber, struct berval *bv, - int alloc )); + int options )); LBER_F( ber_tag_t ) ber_get_stringa LDAP_P(( @@ -316,9 +323,19 @@ ber_scanf LDAP_P(( LDAP_CONST char *fmt, ... )); +LBER_F( int ) +ber_decode_oid LDAP_P(( + struct berval *in, + struct berval *out )); + /* * in encode.c */ +LBER_F( int ) +ber_encode_oid LDAP_P(( + struct berval *in, + struct berval *out )); + typedef int (*BEREncodeCallback) LDAP_P(( BerElement *ber, void *data )); @@ -401,6 +418,11 @@ ber_printf LDAP_P(( * in io.c: */ +LBER_F( ber_slen_t ) +ber_skip_data LDAP_P(( + BerElement *ber, + ber_len_t len )); + LBER_F( ber_slen_t ) ber_read LDAP_P(( BerElement *ber, diff --git a/include/ldap.h b/include/ldap.h index 759b9ba01d..2e55abd007 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -141,6 +141,7 @@ LDAP_BEGIN_DECL #define LDAP_OPT_X_TLS_CONNECT_ARG 0x600d #define LDAP_OPT_X_TLS_DHFILE 0x600e #define LDAP_OPT_X_TLS_NEWCTX 0x600f +#define LDAP_OPT_X_TLS_CRLFILE 0x6010 /* GNUtls only */ #define LDAP_OPT_X_TLS_NEVER 0 #define LDAP_OPT_X_TLS_HARD 1 @@ -288,11 +289,22 @@ typedef struct ldapcontrol { #define LDAP_CONTROL_X_SEARCH_OPTIONS "1.2.840.113556.1.4.1340" #define LDAP_SEARCH_FLAG_DOMAIN_SCOPE 1 /* do not generate referrals */ #define LDAP_SEARCH_FLAG_PHANTOM_ROOT 2 /* search all subordinate NCs */ +#define LDAP_CONTROL_X_TREE_DELETE "1.2.840.113556.1.4.805" /* MS Active Directory controls - not implemented in slapd(8) */ -#define LDAP_CONTROL_X_TREE_DELETE "1.2.840.113556.1.4.805" #define LDAP_CONTROL_X_EXTENDED_DN "1.2.840.113556.1.4.529" +#ifdef LDAP_DEVEL +/* */ +#define LDAP_CONTROL_X_SESSION_TRACKING "1.3.6.1.4.1.21008.108.63.1" +#define LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID \ + LDAP_CONTROL_X_SESSION_TRACKING ".1" +#define LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID \ + LDAP_CONTROL_X_SESSION_TRACKING ".2" +#define LDAP_CONTROL_X_SESSION_TRACKING_USERNAME \ + LDAP_CONTROL_X_SESSION_TRACKING ".3" +#endif /* LDAP_DEVEL */ + /* various expired works */ /* LDAP Duplicated Entry Control Extension *//* not implemented in slapd(8) */ #define LDAP_CONTROL_DUPENT_REQUEST "2.16.840.1.113719.1.27.101.1" @@ -929,17 +941,33 @@ ldap_set_urllist_proc LDAP_P(( /* * in controls.c: */ +#if LDAP_DEPRECATED LDAP_F( int ) -ldap_create_control LDAP_P(( +ldap_create_control LDAP_P(( /* deprecated, use ldap_control_create */ LDAP_CONST char *requestOID, BerElement *ber, int iscritical, LDAPControl **ctrlp )); LDAP_F( LDAPControl * ) -ldap_find_control LDAP_P(( +ldap_find_control LDAP_P(( /* deprecated, use ldap_control_find */ LDAP_CONST char *oid, LDAPControl **ctrls )); +#endif + +LDAP_F( int ) +ldap_control_create LDAP_P(( + LDAP_CONST char *requestOID, + int iscritical, + struct berval *value, + int dupval, + LDAPControl **ctrlp )); + +LDAP_F( LDAPControl * ) +ldap_control_find LDAP_P(( + LDAP_CONST char *oid, + LDAPControl **ctrls, + LDAPControl ***nextctrlp )); LDAP_F( void ) ldap_control_free LDAP_P(( @@ -949,6 +977,14 @@ LDAP_F( void ) ldap_controls_free LDAP_P(( LDAPControl **ctrls )); +LDAP_F( LDAPControl ** ) +ldap_controls_dup LDAP_P(( + LDAPControl *LDAP_CONST *controls )); + +LDAP_F( LDAPControl * ) +ldap_control_dup LDAP_P(( + LDAP_CONST LDAPControl *c )); + /* * in dnssrv.c: */ @@ -2273,5 +2309,39 @@ LDAP_F( int ) ldap_sync_poll LDAP_P(( ldap_sync_t *ls )); +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + +/* + * in stctrl.c + */ +LDAP_F( int ) +ldap_create_session_tracking_value LDAP_P(( + LDAP *ld, + char *sessionSourceIp, + char *sessionSourceName, + char *formatOID, + struct berval *sessionTrackingIdentifier, + struct berval *value )); + +LDAP_F( int ) +ldap_create_session_tracking LDAP_P(( + LDAP *ld, + char *sessionSourceIp, + char *sessionSourceName, + char *formatOID, + struct berval *sessionTrackingIdentifier, + LDAPControl **ctrlp )); + +LDAP_F( int ) +ldap_parse_session_tracking_control LDAP_P(( + LDAP *ld, + LDAPControl *ctrl, + struct berval *ip, + struct berval *name, + struct berval *oid, + struct berval *id )); + +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ + LDAP_END_DECL #endif /* _LDAP_H */ diff --git a/include/ldap_config.hin b/include/ldap_config.hin index 5d8132b7c4..fcd59493ab 100644 --- a/include/ldap_config.hin +++ b/include/ldap_config.hin @@ -59,6 +59,9 @@ #ifndef LDAP_LIBEXECDIR #define LDAP_LIBEXECDIR "%LIBEXECDIR%" #endif +#ifndef LDAP_MODULEDIR +#define LDAP_MODULEDIR "%MODULEDIR%" +#endif #ifndef LDAP_RUNDIR #define LDAP_RUNDIR "%RUNDIR%" #endif diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h index bc9c90662c..1506983757 100644 --- a/include/ldap_pvt.h +++ b/include/ldap_pvt.h @@ -47,13 +47,20 @@ struct ldap_url_desc; /* avoid pulling in */ #define LDAP_PVT_URL_PARSE_DEF_PORT (0x02U) #define LDAP_PVT_URL_PARSE_NOEMPTY_DN (0x04U) #define LDAP_PVT_URL_PARSE_NODEF_SCOPE (0x08U) -#define LDAP_PVT_URL_PARSE_HISTORIC (LDAP_PVT_URL_PARSE_NODEF_SCOPE | LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_DEF_PORT) +#define LDAP_PVT_URL_PARSE_HISTORIC (LDAP_PVT_URL_PARSE_NODEF_SCOPE | \ + LDAP_PVT_URL_PARSE_NOEMPTY_HOST | \ + LDAP_PVT_URL_PARSE_DEF_PORT) + LDAP_F( int ) ldap_url_parse_ext LDAP_P(( LDAP_CONST char *url, struct ldap_url_desc **ludpp, unsigned flags )); +LDAP_F (int) ldap_url_parselist LDAP_P(( /* deprecated, use ldap_url_parselist_ext() */ + struct ldap_url_desc **ludlist, + const char *url )); + LDAP_F (int) ldap_url_parselist_ext LDAP_P(( struct ldap_url_desc **ludlist, const char *url, @@ -188,12 +195,10 @@ LDAP_F (void) ldap_pvt_hex_unescape LDAP_P(( char *s )); /* controls.c */ struct ldapcontrol; -LDAP_F (struct ldapcontrol *) ldap_control_dup LDAP_P(( - const struct ldapcontrol *ctrl )); - -LDAP_F (struct ldapcontrol **) ldap_controls_dup LDAP_P(( - struct ldapcontrol *const *ctrls )); - +LDAP_F (int) +ldap_pvt_put_control LDAP_P(( + const struct ldapcontrol *c, + BerElement *ber )); LDAP_F (int) ldap_pvt_get_controls LDAP_P(( BerElement *be, struct ldapcontrol ***ctrlsp)); @@ -285,8 +290,7 @@ LDAP_F (int) ldap_pvt_tls_init_def_ctx LDAP_P(( int is_server )); LDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg )); LDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb )); LDAP_F (void *) ldap_pvt_tls_sb_ctx LDAP_P(( Sockbuf *sb )); - -LDAP_F (int) ldap_pvt_tls_init_default_ctx LDAP_P(( void )); +LDAP_F (void) ldap_pvt_tls_ctx_free LDAP_P(( void * )); typedef int LDAPDN_rewrite_dummy LDAP_P (( void *dn, unsigned flags )); @@ -312,7 +316,7 @@ LDAP_END_DECL * If none is available, unsigned long data is used. */ -#if USE_MP_BIGNUM +#ifdef USE_MP_BIGNUM /* * Use OpenSSL's BIGNUM */ @@ -338,7 +342,7 @@ typedef BIGNUM* ldap_pvt_mp_t; #define ldap_pvt_mp_clear(mp) \ do { BN_free((mp)); (mp) = 0; } while (0) -#elif USE_MP_GMP +#elif defined(USE_MP_GMP) /* * Use GNU's multiple precision library */ @@ -367,13 +371,13 @@ typedef mpz_t ldap_pvt_mp_t; * Use unsigned long long */ -#if USE_MP_LONG_LONG +#ifdef USE_MP_LONG_LONG typedef unsigned long long ldap_pvt_mp_t; #define LDAP_PVT_MP_INIT (0LL) -#elif USE_MP_LONG +#elif defined(USE_MP_LONG) typedef unsigned long ldap_pvt_mp_t; #define LDAP_PVT_MP_INIT (0L) -#elif HAVE_LONG_LONG +#elif defined(HAVE_LONG_LONG) typedef unsigned long long ldap_pvt_mp_t; #define LDAP_PVT_MP_INIT (0LL) #else diff --git a/include/ldap_pvt_thread.h b/include/ldap_pvt_thread.h index ddc0302a83..4d6a9d4294 100644 --- a/include/ldap_pvt_thread.h +++ b/include/ldap_pvt_thread.h @@ -36,11 +36,6 @@ typedef ldap_int_thread_rdwr_t ldap_pvt_thread_rdwr_t; typedef ldap_int_thread_rmutex_t ldap_pvt_thread_rmutex_t; #endif /* !LDAP_PVT_THREAD_H_DONE */ -#if 0 && defined(LDAP_DEVEL) -/* must also be defined in slapd.h */ -#define LDAP_PVT_THREAD_POOL_SEM_LOAD_CONTROL -#endif - #define ldap_pvt_thread_equal ldap_int_thread_equal LDAP_F( int ) diff --git a/include/lutil.h b/include/lutil.h index 49ea795193..9e40663201 100644 --- a/include/lutil.h +++ b/include/lutil.h @@ -219,6 +219,13 @@ lutil_pair( ber_socket_t sd[2] ); LDAP_LUTIL_F( size_t ) lutil_uuidstr( char *buf, size_t len ); +LDAP_LUTIL_F( int ) +lutil_uuidstr_from_normalized( + char *uuid, + size_t uuidlen, + char *buf, + size_t buflen ); + /* csn.c */ /* use this macro to allocate buffer for lutil_csnstr */ #define LDAP_LUTIL_CSNSTR_BUFSIZE 64 diff --git a/include/portable.hin b/include/portable.hin index b31e486f17..b4ef095a9f 100644 --- a/include/portable.hin +++ b/include/portable.hin @@ -238,6 +238,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GMP_H +/* define if you have GNUtls */ +#undef HAVE_GNUTLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_GNUTLS_GNUTLS_H + /* if you have GNU Pth */ #undef HAVE_GNU_PTH @@ -610,6 +616,18 @@ /* Define to 1 if `st_blksize' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLKSIZE +/* Define to 1 if `st_fstype' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_FSTYPE + +/* define to 1 if st_fstype is char * */ +#undef HAVE_STRUCT_STAT_ST_FSTYPE_CHAR + +/* define to 1 if st_fstype is int */ +#undef HAVE_STRUCT_STAT_ST_FSTYPE_INT + +/* Define to 1 if `st_vfstype' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_VFSTYPE + /* Define to 1 if you have the header file. */ #undef HAVE_SYNCH_H @@ -644,6 +662,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FSTYP_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H @@ -657,6 +678,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PRIVGRP_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H @@ -690,6 +714,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UUID_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VMOUNT_H + /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H @@ -729,9 +756,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H +/* define if you have uuid_generate() */ +#undef HAVE_UUID_GENERATE + /* define if you have uuid_to_str() */ #undef HAVE_UUID_TO_STR +/* Define to 1 if you have the header file. */ +#undef HAVE_UUID_UUID_H + /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF @@ -933,6 +966,9 @@ /* define for Dynamic List overlay */ #undef SLAPD_OVER_DYNLIST +/* define for Reverse Group Membership overlay */ +#undef SLAPD_OVER_MEMBEROF + /* define for Password Policy overlay */ #undef SLAPD_OVER_PPOLICY @@ -1015,6 +1051,9 @@ first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN +/* Define to the type of arg 3 for `accept'. */ +#undef ber_socklen_t + /* Define to `char *' if does not define. */ #undef caddr_t @@ -1042,7 +1081,7 @@ /* define to snprintf routine */ #undef snprintf -/* Define to `int' if does not define. */ +/* Define like ber_socklen_t if does not define. */ #undef socklen_t /* Define to `signed int' if does not define. */ diff --git a/include/slapi-plugin.h b/include/slapi-plugin.h index b3589058f2..3076bc9c22 100644 --- a/include/slapi-plugin.h +++ b/include/slapi-plugin.h @@ -31,9 +31,9 @@ typedef struct slapi_attr Slapi_Attr; typedef struct slapi_value Slapi_Value; typedef struct slapi_valueset Slapi_ValueSet; typedef struct slapi_filter Slapi_Filter; -typedef struct slap_backend_db Slapi_Backend; -typedef struct slap_op Slapi_Operation; -typedef struct slap_conn Slapi_Connection; +typedef struct BackendDB Slapi_Backend; +typedef struct Operation Slapi_Operation; +typedef struct Connection Slapi_Connection; typedef struct slapi_dn Slapi_DN; typedef struct slapi_rdn Slapi_RDN; typedef struct slapi_mod Slapi_Mod; diff --git a/libraries/liblber/bprint.c b/libraries/liblber/bprint.c index 9bfc34f01e..51a958f0ab 100644 --- a/libraries/liblber/bprint.c +++ b/libraries/liblber/bprint.c @@ -265,10 +265,10 @@ ber_dump( len = ber_pvt_ber_write(ber); } - sprintf( buf, "ber_dump: buf=0x%08lx ptr=0x%08lx end=0x%08lx len=%ld\n", - (long) ber->ber_buf, - (long) ber->ber_ptr, - (long) ber->ber_end, + sprintf( buf, "ber_dump: buf=%p ptr=%p end=%p len=%ld\n", + ber->ber_buf, + ber->ber_ptr, + ber->ber_end, (long) len ); (void) (*ber_pvt_log_print)( buf ); @@ -303,10 +303,10 @@ ber_sos_dump( (*ber_pvt_log_print)( "*** sos dump ***\n" ); while ( sos != NULL ) { - sprintf( buf, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n", + sprintf( buf, "ber_sos_dump: clen %ld first %p ptr %p\n", (long) sos->sos_clen, - (long) sos->sos_first, - (long) sos->sos_ptr ); + sos->sos_first, + sos->sos_ptr ); (*ber_pvt_log_print)( buf ); sprintf( buf, " current len %ld contents:\n", diff --git a/libraries/liblber/decode.c b/libraries/liblber/decode.c index 7e1343f926..f2261e7bd5 100644 --- a/libraries/liblber/decode.c +++ b/libraries/liblber/decode.c @@ -45,6 +45,52 @@ static ber_len_t ber_getnint LDAP_P(( ber_int_t *num, ber_len_t len )); +/* out->bv_len should be the buffer size on input */ +int +ber_decode_oid( BerValue *in, BerValue *out ) +{ + const unsigned char *der; + unsigned long val; + unsigned val1; + ber_len_t i; + char *ptr; + + assert( in != NULL ); + assert( out != NULL ); + + /* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */ + if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len ) + return -1; + + ptr = NULL; + der = (unsigned char *) in->bv_val; + val = 0; + for ( i=0; i < in->bv_len; i++ ) { + val |= der[i] & 0x7f; + if ( !( der[i] & 0x80 )) { + if ( ptr == NULL ) { + /* Initial "x.y": val=x*40+y, x<=2, y<40 if x=2 */ + ptr = out->bv_val; + val1 = (val < 80 ? val/40 : 2); + val -= val1*40; + ptr += sprintf( ptr, "%u", val1 ); + } + ptr += sprintf( ptr, ".%lu", val ); + val = 0; + } else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) { + val <<= 7; + } else { + /* val would overflow, or is 0 from invalid initial 0x80 octet */ + return -1; + } + } + if ( ptr == NULL || val != 0 ) + return -1; + + out->bv_len = ptr - out->bv_val; + return 0; +} + /* return the tag - LBER_DEFAULT returned means trouble */ ber_tag_t ber_get_tag( BerElement *ber ) @@ -373,7 +419,7 @@ ber_get_stringbvl( bgbvr *b, ber_len_t *rlen ) case BvOff: *b->res.ba = ber_memalloc_x( (n+1) * b->siz, b->ber->ber_memctx ); if ( *b->res.ba == NULL ) return LBER_DEFAULT; - ((struct berval *)((long)(*b->res.ba) + n*b->siz + + ((struct berval *)((char *)(*b->res.ba) + n*b->siz + b->off))->bv_val = NULL; break; } @@ -406,7 +452,7 @@ ber_get_stringbvl( bgbvr *b, ber_len_t *rlen ) *bvp = bv; break; case BvOff: - *(BerVarray)((long)(*b->res.ba)+n*b->siz+b->off) = bv; + *(BerVarray)((char *)(*b->res.ba)+n*b->siz+b->off) = bv; break; } } @@ -437,7 +483,7 @@ nomem: } ber_tag_t -ber_get_stringbv( BerElement *ber, struct berval *bv, int alloc ) +ber_get_stringbv( BerElement *ber, struct berval *bv, int option ) { ber_tag_t tag; @@ -455,7 +501,7 @@ ber_get_stringbv( BerElement *ber, struct berval *bv, int alloc ) return LBER_DEFAULT; } - if ( alloc ) { + if ( option & LBER_BV_ALLOC ) { bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, ber->ber_memctx ); if ( bv->bv_val == NULL ) { @@ -474,13 +520,14 @@ ber_get_stringbv( BerElement *ber, struct berval *bv, int alloc ) ber->ber_ptr += bv->bv_len; } ber->ber_tag = *(unsigned char *)ber->ber_ptr; - bv->bv_val[bv->bv_len] = '\0'; + if ( !( option & LBER_BV_NOTERM )) + bv->bv_val[bv->bv_len] = '\0'; return tag; } ber_tag_t -ber_get_stringbv_null( BerElement *ber, struct berval *bv, int alloc ) +ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option ) { ber_tag_t tag; @@ -504,7 +551,7 @@ ber_get_stringbv_null( BerElement *ber, struct berval *bv, int alloc ) return tag; } - if ( alloc ) { + if ( option & LBER_BV_ALLOC ) { bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1, ber->ber_memctx ); if ( bv->bv_val == NULL ) { @@ -523,7 +570,8 @@ ber_get_stringbv_null( BerElement *ber, struct berval *bv, int alloc ) ber->ber_ptr += bv->bv_len; } ber->ber_tag = *(unsigned char *)ber->ber_ptr; - bv->bv_val[bv->bv_len] = '\0'; + if ( !( option & LBER_BV_NOTERM )) + bv->bv_val[bv->bv_len] = '\0'; return tag; } @@ -536,7 +584,7 @@ ber_get_stringa( BerElement *ber, char **buf ) assert( buf != NULL ); - tag = ber_get_stringbv( ber, &bv, 1 ); + tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC ); *buf = bv.bv_val; return tag; @@ -550,7 +598,7 @@ ber_get_stringa_null( BerElement *ber, char **buf ) assert( buf != NULL ); - tag = ber_get_stringbv_null( ber, &bv, 1 ); + tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC ); *buf = bv.bv_val; return tag; @@ -570,7 +618,7 @@ ber_get_stringal( BerElement *ber, struct berval **bv ) return LBER_DEFAULT; } - tag = ber_get_stringbv( ber, *bv, 1 ); + tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC ); if ( tag == LBER_DEFAULT ) { LBER_FREE( *bv ); *bv = NULL; @@ -811,7 +859,7 @@ ber_scanf ( BerElement *ber, case 'o': /* octet string in a supplied berval */ bval = va_arg( ap, struct berval * ); - rc = ber_get_stringbv( ber, bval, 1 ); + rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC ); break; case 'O': /* octet string - allocate & include length */ @@ -840,7 +888,7 @@ ber_scanf ( BerElement *ber, bgbvr cookie = { ChArray }; cookie.ber = ber; cookie.res.c = va_arg( ap, char *** ); - cookie.alloc = 1; + cookie.alloc = LBER_BV_ALLOC; rc = ber_get_stringbvl( &cookie, NULL ); break; } @@ -850,7 +898,7 @@ ber_scanf ( BerElement *ber, bgbvr cookie = { BvVec }; cookie.ber = ber; cookie.res.bv = va_arg( ap, struct berval *** ); - cookie.alloc = 1; + cookie.alloc = LBER_BV_ALLOC; rc = ber_get_stringbvl( &cookie, NULL ); break; } @@ -860,7 +908,7 @@ ber_scanf ( BerElement *ber, bgbvr cookie = { BvArray }; cookie.ber = ber; cookie.res.ba = va_arg( ap, struct berval ** ); - cookie.alloc = 1; + cookie.alloc = LBER_BV_ALLOC; rc = ber_get_stringbvl( &cookie, NULL ); break; } diff --git a/libraries/liblber/encode.c b/libraries/liblber/encode.c index 4272a5d9cf..9b20518ba3 100644 --- a/libraries/liblber/encode.c +++ b/libraries/liblber/encode.c @@ -30,6 +30,7 @@ #include "portable.h" +#include #include #include @@ -177,6 +178,63 @@ ber_put_len( BerElement *ber, ber_len_t len, int nosos ) return rc == i ? i+1 : -1; } +/* out->bv_len should be the buffer size on input */ +int +ber_encode_oid( BerValue *in, BerValue *out ) +{ + unsigned char *der; + unsigned long val1, val; + int i, j, len; + char *ptr, *end, *inend; + + assert( in != NULL ); + assert( out != NULL ); + + if ( !out->bv_val || out->bv_len < in->bv_len/2 ) + return -1; + + der = (unsigned char *) out->bv_val; + ptr = in->bv_val; + inend = ptr + in->bv_len; + + /* OIDs start with <0-1>.<0-39> or 2., DER-encoded 40*val1+val2 */ + if ( !isdigit( (unsigned char) *ptr )) return -1; + val1 = strtoul( ptr, &end, 10 ); + if ( end == ptr || val1 > 2 ) return -1; + if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1; + val = strtoul( end, &ptr, 10 ); + if ( ptr == end ) return -1; + if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1; + val += val1 * 40; + + for (;;) { + if ( ptr > inend ) return -1; + + len = 0; + do { + der[len++] = (val & 0xff) | 0x80; + } while ( (val >>= 7) != 0 ); + der[0] &= 0x7f; + for ( i = 0, j = len; i < --j; i++ ) { + unsigned char tmp = der[i]; + der[i] = der[j]; + der[j] = tmp; + } + der += len; + if ( ptr == inend ) + break; + + if ( *ptr++ != '.' ) return -1; + if ( !isdigit( (unsigned char) *ptr )) return -1; + val = strtoul( ptr, &end, 10 ); + if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1; + ptr = end; + } + + out->bv_len = (char *)der - out->bv_val; + return 0; +} + static int ber_put_int_or_enum( BerElement *ber, diff --git a/libraries/liblber/io.c b/libraries/liblber/io.c index 503735819f..4f4afa390f 100644 --- a/libraries/liblber/io.c +++ b/libraries/liblber/io.c @@ -47,6 +47,25 @@ #include "lber-int.h" #include "ldap_log.h" +ber_slen_t +ber_skip_data( + BerElement *ber, + ber_len_t len ) +{ + ber_len_t actuallen, nleft; + + assert( ber != NULL ); + + assert( LBER_VALID( ber ) ); + + nleft = ber_pvt_ber_remaining( ber ); + actuallen = nleft < len ? nleft : len; + ber->ber_ptr += actuallen; + ber->ber_tag = *(unsigned char *)ber->ber_ptr; + + return( (ber_slen_t) actuallen ); +} + ber_slen_t ber_read( BerElement *ber, @@ -185,11 +204,8 @@ ber_free_buf( BerElement *ber ) void ber_free( BerElement *ber, int freebuf ) { -#ifdef LDAP_MEMORY_DEBUG - assert( ber != NULL ); -#endif - if( ber == NULL ) { + LDAP_MEMORY_DEBUG_ASSERT( ber != NULL ); return; } diff --git a/libraries/liblber/lber-int.h b/libraries/liblber/lber-int.h index 4e73a58ebb..e2657d2eb1 100644 --- a/libraries/liblber/lber-int.h +++ b/libraries/liblber/lber-int.h @@ -47,6 +47,11 @@ LBER_V (BER_ERRNO_FN) ber_int_errno_fn; #ifdef LDAP_MEMORY_DEBUG LBER_V (long) ber_int_meminuse; #endif +#if defined(LDAP_MEMORY_DEBUG) && ((LDAP_MEMORY_DEBUG +0) & 2) +# define LDAP_MEMORY_DEBUG_ASSERT assert +#else +# define LDAP_MEMORY_DEBUG_ASSERT(expr) ((void) 0) +#endif struct lber_options { short lbo_valid; @@ -99,9 +104,13 @@ struct sockbuf { #define sb_options sb_opts.lbo_options #define sb_debug sb_opts.lbo_debug ber_socket_t sb_fd; + ber_len_t sb_max_incoming; unsigned int sb_trans_needs_read:1; unsigned int sb_trans_needs_write:1; - ber_len_t sb_max_incoming; +#ifdef LDAP_PF_LOCAL_SENDMSG + char sb_ungetlen; + char sb_ungetbuf[8]; +#endif }; #define SOCKBUF_VALID( sb ) ( (sb)->sb_valid == LBER_VALID_SOCKBUF ) @@ -116,6 +125,14 @@ struct seqorset { }; +/* + * decode.c, encode.c + */ + +/* Simplest OID max-DER-component to implement in both decode and encode */ +#define LBER_OID_COMPONENT_MAX ((unsigned long)-1 - 128) + + /* * io.c */ diff --git a/libraries/liblber/memory.c b/libraries/liblber/memory.c index 0681869862..94ef772d97 100644 --- a/libraries/liblber/memory.c +++ b/libraries/liblber/memory.c @@ -24,13 +24,15 @@ #include #endif -#if LDAP_MEMORY_DEBUG +#ifdef LDAP_MEMORY_DEBUG /* * LDAP_MEMORY_DEBUG should only be enabled for the purposes of * debugging memory management within OpenLDAP libraries and slapd. - * It should only be enabled by an experienced developer as it - * causes the inclusion of numerous assert()'s, many of which may - * be triggered by a prefectly valid program. + * + * It should only be enabled by an experienced developer as it causes + * the inclusion of numerous assert()'s, many of which may be triggered + * by a prefectly valid program. If LDAP_MEMORY_DEBUG & 2 is true, + * that includes asserts known to break both slapd and current clients. * * The code behind this macro is subject to change as needed to * support this testing. @@ -71,6 +73,7 @@ static const struct ber_mem_hdr ber_int_mem_hdr = { LBER_MEM_JUNK, 0, 0 }; * put allocations/frees together. It is then a simple matter to write a script * to find any allocations that don't have a buffer free function. */ +long ber_int_meminuse = 0; #ifdef LDAP_MEMORY_TRACE static ber_int_t sequence = 0; #endif @@ -191,11 +194,8 @@ ber_memalloc_x( ber_len_t s, void *ctx ) { void *new; -#ifdef LDAP_MEMORY_DEBUG - assert( s != 0 ); -#endif - if( s == 0 ) { + LDAP_MEMORY_DEBUG_ASSERT( s != 0 ); return NULL; } @@ -247,11 +247,8 @@ ber_memcalloc_x( ber_len_t n, ber_len_t s, void *ctx ) { void *new; -#ifdef LDAP_MEMORY_DEBUG - assert( n != 0 && s != 0); -#endif - if( n == 0 || s == 0 ) { + LDAP_MEMORY_DEBUG_ASSERT( n != 0 && s != 0); return NULL; } diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index 353d526320..176122ec2a 100644 --- a/libraries/liblber/sockbuf.c +++ b/libraries/liblber/sockbuf.c @@ -150,6 +150,20 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) ret = 1; break; + case LBER_SB_OPT_UNGET_BUF: +#ifdef LDAP_PF_LOCAL_SENDMSG + sb->sb_ungetlen = ((struct berval *)arg)->bv_len; + if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) { + AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val, + sb->sb_ungetlen ); + ret = 1; + } else { + sb->sb_ungetlen = 0; + ret = -1; + } +#endif + break; + default: ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg ); break; @@ -325,7 +339,7 @@ ber_pvt_sb_do_write( Sockbuf_IO_Desc *sbiod, Sockbuf_Buf *buf_out ) int ber_pvt_socket_set_nonblock( ber_socket_t sd, int nb ) { -#if HAVE_FCNTL +#ifdef HAVE_FCNTL int flags = fcntl( sd, F_GETFL); if( nb ) { flags |= O_NONBLOCK; @@ -704,6 +718,24 @@ sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); +#ifdef LDAP_PF_LOCAL_SENDMSG + if ( sbiod->sbiod_sb->sb_ungetlen ) { + ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; + if ( blen > len ) + blen = len; + AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); + buf = (char *) buf + blen; + len -= blen; + sbiod->sbiod_sb->sb_ungetlen -= blen; + if ( sbiod->sbiod_sb->sb_ungetlen ) { + AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, + sbiod->sbiod_sb->sb_ungetbuf+blen, + sbiod->sbiod_sb->sb_ungetlen ); + } + if ( len == 0 ) + return blen; + } +#endif return read( sbiod->sbiod_sb->sb_fd, buf, len ); } @@ -873,7 +905,7 @@ static ber_slen_t sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) { ber_slen_t rc; - socklen_t addrlen; + ber_socklen_t addrlen; struct sockaddr *src; assert( sbiod != NULL ); @@ -882,7 +914,7 @@ sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) addrlen = sizeof( struct sockaddr ); src = buf; - buf += addrlen; + buf = (char *) buf + addrlen; len -= addrlen; rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen ); @@ -900,7 +932,7 @@ sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) assert( buf != NULL ); dst = buf; - buf += sizeof( struct sockaddr ); + buf = (char *) buf + sizeof( struct sockaddr ); len -= sizeof( struct sockaddr ); rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in index 8b62c45cc1..c031db0738 100644 --- a/libraries/libldap/Makefile.in +++ b/libraries/libldap/Makefile.in @@ -26,7 +26,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \ request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \ init.c options.c print.c string.c util-int.c schema.c \ charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \ - turn.c ppolicy.c dds.c txn.c ldap_sync.c + turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ controls.lo messages.lo references.lo extended.lo cyrus.lo \ @@ -37,7 +37,7 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \ - turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo + turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c index 43e2f342c8..d72483ecda 100644 --- a/libraries/libldap/abandon.c +++ b/libraries/libldap/abandon.c @@ -224,8 +224,9 @@ start_again:; i = ++(ld)->ld_msgid; #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { - err = ber_write( ber, ld->ld_options.ldo_peer, - sizeof(struct sockaddr), 0); + struct sockaddr sa = {0}; + /* dummy, filled with ldo_peer in request.c */ + err = ber_write( ber, &sa, sizeof(sa), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2 ) diff --git a/libraries/libldap/addentry.c b/libraries/libldap/addentry.c index 229524cd2e..db4568dc7f 100644 --- a/libraries/libldap/addentry.c +++ b/libraries/libldap/addentry.c @@ -64,6 +64,9 @@ ldap_add_result_entry( LDAPMessage **list, LDAPMessage *e ) assert( e != NULL ); e->lm_chain = *list; - e->lm_chain_tail = (*list)->lm_chain_tail; + if ( *list ) + e->lm_chain_tail = (*list)->lm_chain_tail; + else + e->lm_chain_tail = e; *list = e; } diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c index faca9839ec..059dc5266f 100644 --- a/libraries/libldap/controls.c +++ b/libraries/libldap/controls.c @@ -51,6 +51,36 @@ * } */ +int +ldap_pvt_put_control( + const LDAPControl *c, + BerElement *ber ) +{ + if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) { + return LDAP_ENCODING_ERROR; + } + + if ( c->ldctl_iscritical /* only if true */ + && ( ber_printf( ber, "b", + (ber_int_t) c->ldctl_iscritical ) == -1 ) ) + { + return LDAP_ENCODING_ERROR; + } + + if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */ + && ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) ) + { + return LDAP_ENCODING_ERROR; + } + + if ( ber_printf( ber, /*{*/"N}" ) == -1 ) { + return LDAP_ENCODING_ERROR; + } + + return LDAP_SUCCESS; +} + + /* * ldap_int_put_controls */ @@ -97,32 +127,8 @@ ldap_int_put_controls( } for( c = ctrls ; *c != NULL; c++ ) { - if ( ber_printf( ber, "{s" /*}*/, - (*c)->ldctl_oid ) == -1 ) - { - ld->ld_errno = LDAP_ENCODING_ERROR; - return ld->ld_errno; - } - - if( (*c)->ldctl_iscritical /* only if true */ - && ( ber_printf( ber, "b", - (ber_int_t) (*c)->ldctl_iscritical ) == -1 ) ) - { - ld->ld_errno = LDAP_ENCODING_ERROR; - return ld->ld_errno; - } - - if( (*c)->ldctl_value.bv_val != NULL /* only if we have a value */ - && ( ber_printf( ber, "O", - &((*c)->ldctl_value) ) == -1 ) ) - { - ld->ld_errno = LDAP_ENCODING_ERROR; - return ld->ld_errno; - } - - - if( ber_printf( ber, /*{*/"N}" ) == -1 ) { - ld->ld_errno = LDAP_ENCODING_ERROR; + ld->ld_errno = ldap_pvt_put_control( *c, ber ); + if ( ld->ld_errno != LDAP_SUCCESS ) { return ld->ld_errno; } } @@ -231,7 +237,7 @@ int ldap_pvt_get_controls( if( tag == LBER_OCTETSTRING ) { tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); } else { - tctrl->ldctl_value.bv_val = NULL; + BER_BVZERO( &tctrl->ldctl_value ); } *ctrls = tctrls; @@ -246,9 +252,7 @@ int ldap_pvt_get_controls( void ldap_control_free( LDAPControl *c ) { -#ifdef LDAP_MEMORY_DEBUG - assert( c != NULL ); -#endif + LDAP_MEMORY_DEBUG_ASSERT( c != NULL ); if ( c != NULL ) { if( c->ldctl_oid != NULL) { @@ -269,9 +273,7 @@ ldap_control_free( LDAPControl *c ) void ldap_controls_free( LDAPControl **controls ) { -#ifdef LDAP_MEMORY_DEBUG - assert( controls != NULL ); -#endif + LDAP_MEMORY_DEBUG_ASSERT( controls != NULL ); if ( controls != NULL ) { int i; @@ -354,6 +356,7 @@ ldap_control_dup( const LDAPControl *c ) } } else { + /* FIXME: how can a control have null OID? */ new->ldctl_oid = NULL; } @@ -385,7 +388,9 @@ ldap_control_dup( const LDAPControl *c ) return new; } - +/* + * Find a LDAPControl - deprecated + */ LDAPControl * ldap_find_control( LDAP_CONST char *oid, @@ -405,21 +410,38 @@ ldap_find_control( } /* - ldap_create_control - - Internal function to create an LDAP control from the encoded BerElement. - - requestOID (IN) The OID to use in creating the control. - - ber (IN) The encoded BerElement to use in creating the control. - - iscritical (IN) 0 - Indicates the control is not critical to the operation. - non-zero - The control is critical to the operation. - - ctrlp (OUT) Returns a pointer to the LDAPControl created. This control - SHOULD be freed by calling ldap_control_free() when done. ----*/ + * Find a LDAPControl + */ +LDAPControl * +ldap_control_find( + LDAP_CONST char *oid, + LDAPControl **ctrls, + LDAPControl ***nextctrlp ) +{ + if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) { + return NULL; + } + + for( ; *ctrls != NULL; ctrls++ ) { + if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { + if ( nextctrlp != NULL ) { + *nextctrlp = ctrls + 1; + } + + return *ctrls; + } + } + + if ( nextctrlp != NULL ) { + *nextctrlp = NULL; + } + return NULL; +} + +/* + * Create a LDAPControl, optionally from ber - deprecated + */ int ldap_create_control( LDAP_CONST char *requestOID, @@ -430,7 +452,6 @@ ldap_create_control( LDAPControl *ctrl; assert( requestOID != NULL ); - assert( ber != NULL ); assert( ctrlp != NULL ); ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); @@ -438,7 +459,8 @@ ldap_create_control( return LDAP_NO_MEMORY; } - if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { + BER_BVZERO(&ctrl->ldctl_value); + if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) { LDAP_FREE( ctrl ); return LDAP_NO_MEMORY; } @@ -455,6 +477,54 @@ ldap_create_control( return LDAP_SUCCESS; } +/* + * Create a LDAPControl, optionally from value + */ +int +ldap_control_create( + LDAP_CONST char *requestOID, + int iscritical, + struct berval *value, + int dupval, + LDAPControl **ctrlp ) +{ + LDAPControl *ctrl; + + assert( requestOID != NULL ); + assert( ctrlp != NULL ); + + ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 ); + if ( ctrl == NULL ) { + return LDAP_NO_MEMORY; + } + + ctrl->ldctl_iscritical = iscritical; + if ( requestOID != NULL ) { + ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); + if ( ctrl->ldctl_oid == NULL ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + } + + if ( value && !BER_BVISNULL( value ) ) { + if ( dupval ) { + ber_dupbv( &ctrl->ldctl_value, value ); + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + + } else { + ctrl->ldctl_value = *value; + } + } + + *ctrlp = ctrl; + + return LDAP_SUCCESS; +} + /* * check for critical client controls and bitch if present * if we ever support critical controls, we'll have to diff --git a/libraries/libldap/dds.c b/libraries/libldap/dds.c index 88ec16f4bd..e3c986d89e 100644 --- a/libraries/libldap/dds.c +++ b/libraries/libldap/dds.c @@ -113,13 +113,14 @@ ldap_refresh( rc = ber_flatten2( ber, &bv, 0 ); if ( rc < 0 ) { - ld->ld_errno = LDAP_ENCODING_ERROR; - return ld->ld_errno; + rc = ld->ld_errno = LDAP_ENCODING_ERROR; + goto done; } rc = ldap_extended_operation( ld, LDAP_EXOP_REFRESH, &bv, sctrls, cctrls, msgidp ); +done:; ber_free( ber, 1 ); return rc; diff --git a/libraries/libldap/extended.c b/libraries/libldap/extended.c index 644180de0e..5a6efda9f1 100644 --- a/libraries/libldap/extended.c +++ b/libraries/libldap/extended.c @@ -315,6 +315,7 @@ ldap_parse_intermediate ( if( retoidp != NULL ) *retoidp = NULL; if( retdatap != NULL ) *retdatap = NULL; + if( serverctrls != NULL ) *serverctrls = NULL; ber = ber_dup( res->lm_ber ); diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index 161beca9f0..d432871725 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -2368,12 +2368,12 @@ strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) /* * Length of the (supposedly) AD canonical string representation, - * accounting for escaped hex of UTF-8 chars + * accounting for chars that need to be escaped */ static int strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ) { - ber_len_t l; + ber_len_t l, cl; char *p; assert( val != NULL ); @@ -2384,37 +2384,31 @@ strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len ) return( 0 ); } - if ( flags & LDAP_AVA_NONPRINTABLE ) { - /* - * FIXME: Turn the value into a binary encoded BER? - */ - return( -1 ); - - } else { - for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { - if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) { - l += 2; - - } else { - l++; - } + for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) { + cl = LDAP_UTF8_CHARLEN2( p, cl ); + if ( cl == 0 ) { + /* illegal utf-8 char */ + return -1; + } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) { + l += 2; + } else { + l += cl; } } *len = l; - + return( 0 ); } /* - * convert to (supposedly) AD string representation, - * escaping with hex the UTF-8 stuff; + * convert to (supposedly) AD string representation, * assume the destination has enough room for escaping */ static int strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) { - ber_len_t s, d; + ber_len_t s, d, cl; assert( val != NULL ); assert( str != NULL ); @@ -2425,24 +2419,20 @@ strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len ) return( 0 ); } - if ( flags & LDAP_AVA_NONPRINTABLE ) { - /* - * FIXME: Turn the value into a binary encoded BER? - */ - *len = 0; - return( -1 ); - - } else { - - /* - * we assume the string has enough room for the hex encoding - * of the value - */ + /* + * we assume the string has enough room for the escaping + * of the value + */ - for ( s = 0, d = 0; s < val->bv_len; ) { - if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) { - str[ d++ ] = '\\'; - } + for ( s = 0, d = 0; s < val->bv_len; ) { + cl = LDAP_UTF8_CHARLEN2( val->bv_val+s, cl ); + if ( cl == 0 ) { + /* illegal utf-8 char */ + return -1; + } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD(val->bv_val[ s ]) ) { + str[ d++ ] = '\\'; + } + for (; cl--;) { str[ d++ ] = val->bv_val[ s++ ]; } } @@ -3309,202 +3299,3 @@ return_results:; return( rc ); } -#ifdef HAVE_TLS -#include -#include - -/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN. - * x509_name must be an (X509_NAME *). If func is non-NULL, the - * constructed DN will use numeric OIDs to identify attributeTypes, - * and the func() will be invoked to rewrite the DN with the given - * flags. - * - * Otherwise the DN will use shortNames as defined in the OpenSSL - * library. - * - * It's preferable to let slapd do the OID to attributeType mapping, - * because the OpenSSL tables are known to have many typos in versions - * up to (at least) 0.9.6c. However, the LDAP client has no schema tables, - * so we're forced to use OpenSSL's mapping there. - * -- Howard Chu 2002-04-18 - */ - -int -ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func, - unsigned flags ) -{ - LDAPDN newDN; - LDAPRDN newRDN; - LDAPAVA *newAVA, *baseAVA; - X509_NAME_ENTRY *ne; - ASN1_OBJECT *obj; - ASN1_STRING *str; - char oids[8192], *oidptr = oids, *oidbuf = NULL; - void *ptrs[2048]; - int i, j, k = 0, navas, nrdns, rc = LDAP_SUCCESS; - int set = -1; - size_t dnsize, oidrem = sizeof(oids), oidsize = 0; - int csize; - - struct berval Val; - - assert( bv != NULL ); - bv->bv_len = 0; - bv->bv_val = NULL; - - /* Get the number of AVAs. This is not necessarily the same as - * the number of RDNs. - */ - navas = X509_NAME_entry_count( x509_name ); - - /* Get the last element, to see how many RDNs there are */ - ne = X509_NAME_get_entry( x509_name, navas - 1 ); - nrdns = ne->set + 1; - - /* Allocate the DN/RDN/AVA stuff as a single block */ - dnsize = sizeof(LDAPRDN) * (nrdns+1); - dnsize += sizeof(LDAPAVA *) * (navas+nrdns); - dnsize += sizeof(LDAPAVA) * navas; - if (dnsize > sizeof(ptrs)) { - newDN = (LDAPDN)LDAP_MALLOC( dnsize ); - if ( newDN == NULL ) - return LDAP_NO_MEMORY; - } else { - newDN = (LDAPDN)(char *)ptrs; - } - - newDN[nrdns] = NULL; - newRDN = (LDAPRDN)(newDN + nrdns+1); - newAVA = (LDAPAVA *)(newRDN + navas + nrdns); - baseAVA = newAVA; - - /* Retrieve RDNs in reverse order; LDAP is backwards from X.500. */ - for ( i = nrdns - 1, j = 0; i >= 0; i-- ) { - ne = X509_NAME_get_entry( x509_name, i ); - obj = X509_NAME_ENTRY_get_object( ne ); - str = X509_NAME_ENTRY_get_data( ne ); - - /* If set changed, move to next RDN */ - if ( set != ne->set ) { - /* If this is not the first time, end the - * previous RDN and advance. - */ - if ( j > 0 ) { - newRDN[k] = NULL; - newRDN += k+1; - } - newDN[j++] = newRDN; - - k = 0; - set = ne->set; - } - newAVA->la_private = NULL; - newAVA->la_flags = LDAP_AVA_STRING; - - if ( !func ) { - int n = OBJ_obj2nid( obj ); - - if (n == NID_undef) - goto get_oid; - newAVA->la_attr.bv_val = (char *)OBJ_nid2sn( n ); - newAVA->la_attr.bv_len = strlen( newAVA->la_attr.bv_val ); -#ifdef HAVE_EBCDIC - newAVA->la_attr.bv_val = LDAP_STRDUP( newAVA->la_attr.bv_val ); - __etoa( newAVA->la_attr.bv_val ); - newAVA->la_flags |= LDAP_AVA_FREE_ATTR; -#endif - } else { -get_oid: newAVA->la_attr.bv_val = oidptr; - newAVA->la_attr.bv_len = OBJ_obj2txt( oidptr, oidrem, obj, 1 ); -#ifdef HAVE_EBCDIC - __etoa( newAVA->la_attr.bv_val ); -#endif - oidptr += newAVA->la_attr.bv_len + 1; - oidrem -= newAVA->la_attr.bv_len + 1; - - /* Running out of OID buffer space? */ - if (oidrem < 128) { - if ( oidsize == 0 ) { - oidsize = sizeof(oids) * 2; - oidrem = oidsize; - oidbuf = LDAP_MALLOC( oidsize ); - if ( oidbuf == NULL ) goto nomem; - oidptr = oidbuf; - } else { - char *old = oidbuf; - oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 ); - if ( oidbuf == NULL ) goto nomem; - /* Buffer moved! Fix AVA pointers */ - if ( old != oidbuf ) { - LDAPAVA *a; - long dif = oidbuf - old; - - for (a=baseAVA; a<=newAVA; a++){ - if (a->la_attr.bv_val >= old && - a->la_attr.bv_val <= (old + oidsize)) - a->la_attr.bv_val += dif; - } - } - oidptr = oidbuf + oidsize - oidrem; - oidrem += oidsize; - oidsize *= 2; - } - } - } - Val.bv_val = (char *) str->data; - Val.bv_len = str->length; - switch( str->type ) { - case V_ASN1_UNIVERSALSTRING: - /* This uses 32-bit ISO 10646-1 */ - csize = 4; goto to_utf8; - case V_ASN1_BMPSTRING: - /* This uses 16-bit ISO 10646-1 */ - csize = 2; goto to_utf8; - case V_ASN1_T61STRING: - /* This uses 8-bit, assume ISO 8859-1 */ - csize = 1; -to_utf8: rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value ); - newAVA->la_flags |= LDAP_AVA_FREE_VALUE; - if (rc != LDAP_SUCCESS) goto nomem; - newAVA->la_flags = LDAP_AVA_NONPRINTABLE; - break; - case V_ASN1_UTF8STRING: - newAVA->la_flags = LDAP_AVA_NONPRINTABLE; - /* This is already in UTF-8 encoding */ - case V_ASN1_IA5STRING: - case V_ASN1_PRINTABLESTRING: - /* These are always 7-bit strings */ - newAVA->la_value = Val; - default: - ; - } - newRDN[k] = newAVA; - newAVA++; - k++; - } - newRDN[k] = NULL; - - if ( func ) { - rc = func( newDN, flags, NULL ); - if ( rc != LDAP_SUCCESS ) - goto nomem; - } - - rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL ); - -nomem: - for (;baseAVA < newAVA; baseAVA++) { - if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR) - LDAP_FREE( baseAVA->la_attr.bv_val ); - if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE) - LDAP_FREE( baseAVA->la_value.bv_val ); - } - - if ( oidsize != 0 ) - LDAP_FREE( oidbuf ); - if ( newDN != (LDAPDN)(char *) ptrs ) - LDAP_FREE( newDN ); - return rc; -} -#endif /* HAVE_TLS */ - diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c index 345eb823d3..3f6e3d61e0 100644 --- a/libraries/libldap/init.c +++ b/libraries/libldap/init.c @@ -114,6 +114,9 @@ static const struct ol_attribute { #ifdef HAVE_OPENSSL_CRL {0, ATTR_TLS, "TLS_CRLCHECK", NULL, LDAP_OPT_X_TLS_CRLCHECK}, #endif +#ifdef HAVE_GNUTLS + {0, ATTR_TLS, "TLS_CRL", NULL, LDAP_OPT_X_TLS_CRLFILE}, +#endif #endif @@ -521,6 +524,7 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl #ifdef HAVE_TLS gopts->ldo_tls_connect_cb = NULL; gopts->ldo_tls_connect_arg = NULL; + gopts->ldo_tls_require_cert = LDAP_OPT_X_TLS_DEMAND; #endif gopts->ldo_valid = LDAP_INITIALIZED; diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 5f6f6d5d35..91e9bb8ae9 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -38,7 +38,7 @@ #include #endif -#define SASL_MAX_BUFF_SIZE 65536 +#define SASL_MAX_BUFF_SIZE (0xffffff) #define SASL_MIN_BUFF_SIZE 4096 #endif @@ -154,6 +154,9 @@ struct ldaptls { char *lt_cacertfile; char *lt_cacertdir; char *lt_ciphersuite; +#ifdef HAVE_GNUTLS + char *lt_crlfile; +#endif }; #endif @@ -196,6 +199,7 @@ struct ldapoptions { #define ldo_tls_cacertfile ldo_tls_info.lt_cacertfile #define ldo_tls_cacertdir ldo_tls_info.lt_cacertdir #define ldo_tls_ciphersuite ldo_tls_info.lt_ciphersuite +#define ldo_tls_crlfile ldo_tls_info.lt_crlfile int ldo_tls_mode; int ldo_tls_require_cert; #ifdef HAVE_OPENSSL_CRL @@ -595,10 +599,6 @@ LDAP_F (LDAPURLDesc *) ldap_url_dup LDAP_P(( LDAP_F (LDAPURLDesc *) ldap_url_duplist LDAP_P(( LDAPURLDesc *ludlist )); -LDAP_F (int) ldap_url_parselist LDAP_P(( - LDAPURLDesc **ludlist, - const char *url )); - LDAP_F (int) ldap_url_parsehosts LDAP_P(( LDAPURLDesc **ludlist, const char *hosts, diff --git a/libraries/libldap/ldap.conf b/libraries/libldap/ldap.conf index 00ff0fa1a5..a94cfaab6e 100644 --- a/libraries/libldap/ldap.conf +++ b/libraries/libldap/ldap.conf @@ -5,7 +5,7 @@ # See ldap.conf(5) for details # This file should be world readable but not world writable. -#BASE dc=example, dc=com +#BASE dc=example,dc=com #URI ldap://ldap.example.com ldap://ldap-master.example.com:666 #SIZELIMIT 12 diff --git a/libraries/libldap/ldap_sync.c b/libraries/libldap/ldap_sync.c index 8db70ada28..8eb8933e20 100644 --- a/libraries/libldap/ldap_sync.c +++ b/libraries/libldap/ldap_sync.c @@ -29,34 +29,6 @@ #include "ldap-int.h" #ifdef LDAP_SYNC_TRACE -/* - * used for debug purposes - */ -static char * -print_UUID( char *buf, size_t len, unsigned char *UUID ) -{ - snprintf( buf, len, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x-%02x%02x%02x%02x%02x%02x", - UUID[0], - UUID[1], - UUID[2], - UUID[3], - UUID[4], - UUID[5], - UUID[6], - UUID[7], - UUID[8], - UUID[9], - UUID[10], - UUID[11], - UUID[12], - UUID[13], - UUID[14], - UUID[15] ); - return buf; -} - static const char * ldap_sync_state2str( int state ) { @@ -600,8 +572,9 @@ ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDo for ( i = 0; syncUUIDs[ i ].bv_val != NULL; i++ ) { char buf[ BUFSIZ ]; fprintf( stderr, "\t\t%s\n", - print_UUID( buf, sizeof( buf ), - (unsigned char *)syncUUIDs[ i ].bv_val ) ); + lutil_uuidstr_from_normalized( + syncUUIDs[ i ].bv_val, syncUUIDs[ i ].bv_len, + buf, sizeof( buf ) ) ); } } #endif /* LDAP_SYNC_TRACE */ diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c index 4b7de9e690..7859aa75e3 100644 --- a/libraries/libldap/os-ip.c +++ b/libraries/libldap/os-ip.c @@ -174,7 +174,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) #if defined( notyet ) /* && defined( SO_ERROR ) */ { int so_errno; - socklen_t dummy = sizeof(so_errno); + ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == AC_SOCKET_ERROR ) { @@ -196,7 +196,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) struct sockaddr_in sin; #endif char ch; - socklen_t dummy = sizeof(sin); + ber_socklen_t dummy = sizeof(sin); if ( getpeername( s, (struct sockaddr *) &sin, &dummy ) == AC_SOCKET_ERROR ) { @@ -316,7 +316,7 @@ ldap_int_poll( /* This means the connection failed */ if ( FD_ISSET(s, &efds) ) { int so_errno; - int dummy = sizeof(so_errno); + ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno ) { @@ -350,7 +350,7 @@ ldap_int_poll( static int ldap_pvt_connect(LDAP *ld, ber_socket_t s, - struct sockaddr *sin, socklen_t addrlen, + struct sockaddr *sin, ber_socklen_t addrlen, int async) { int rc, err; @@ -621,7 +621,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb, char * ldap_host_connected_to( Sockbuf *sb, const char *host ) { - socklen_t len; + ber_socklen_t len; #ifdef LDAP_PF_INET6 struct sockaddr_storage sabuf; #else diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c index 4e3a19e5a2..fbec2273e1 100644 --- a/libraries/libldap/os-local.c +++ b/libraries/libldap/os-local.c @@ -120,7 +120,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) #if defined( notyet ) /* && defined( SO_ERROR ) */ { int so_errno; - socklen_t dummy = sizeof(so_errno); + ber_socklen_t dummy = sizeof(so_errno); if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == AC_SOCKET_ERROR ) { @@ -138,7 +138,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) /* error slippery */ struct sockaddr_un sa; char ch; - socklen_t dummy = sizeof(sa); + ber_socklen_t dummy = sizeof(sa); if ( getpeername( s, (struct sockaddr *) &sa, &dummy ) == AC_SOCKET_ERROR ) { @@ -154,12 +154,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) } #undef TRACE -#if !defined(HAVE_GETPEEREID) && \ - !defined(HAVE_GETPEERUCRED) && \ - !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ - defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ - defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) -#define DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG static const char abandonPDU[] = {LDAP_TAG_MESSAGE, 6, LDAP_TAG_MSGID, 1, 0, LDAP_REQ_ABANDON, 1, 0}; #endif @@ -185,13 +180,16 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sa, int async) { if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG /* Send a dummy message with access rights. Remote side will - * obtain our uid/gid by fstat'ing this descriptor. + * obtain our uid/gid by fstat'ing this descriptor. The + * descriptor permissions must match exactly, and we also + * send the socket name, which must also match. */ sendcred: { int fds[2]; + ber_socklen_t salen = sizeof(*sa); if (pipe(fds) == 0) { /* Abandon, noop, has no reply */ struct iovec iov; @@ -230,6 +228,9 @@ sendcred: msg.msg_accrights = (char *)fds; msg.msg_accrightslen = sizeof(int); # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ + getpeername( s, sa, &salen ); + fchmod( fds[0], S_ISUID|S_IRWXU ); + write( fds[1], sa, salen ); sendmsg( s, &msg, 0 ); close(fds[0]); close(fds[1]); @@ -266,7 +267,7 @@ sendcred: if( fd.revents & POLL_WRITE ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); @@ -297,7 +298,7 @@ sendcred: if ( FD_ISSET(s, &wfds) ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); diff --git a/libraries/libldap/pagectrl.c b/libraries/libldap/pagectrl.c index df4978705d..93222406b1 100644 --- a/libraries/libldap/pagectrl.c +++ b/libraries/libldap/pagectrl.c @@ -139,7 +139,6 @@ ldap_create_page_control( LDAPControl **ctrlp ) { struct berval value; - BerElement *ber; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; @@ -149,19 +148,11 @@ ldap_create_page_control( ld->ld_errno = ldap_create_page_control_value( ld, pagesize, cookie, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { - if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { - ld->ld_errno = LDAP_NO_MEMORY; - return LDAP_NO_MEMORY; - } - - ld->ld_errno = ldap_create_control( LDAP_CONTROL_PAGEDRESULTS, - ber, iscritical, ctrlp ); - if ( ld->ld_errno == LDAP_SUCCESS ) { - (*ctrlp)->ldctl_value = value; - } else { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_PAGEDRESULTS, + iscritical, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } - ber_free(ber, 1); } return ld->ld_errno; @@ -256,7 +247,7 @@ ldap_parse_page_control( return ld->ld_errno; } - c = ldap_find_control( LDAP_CONTROL_PAGEDRESULTS, ctrls ); + c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL ); if ( c == NULL ) { /* No page control was found. */ ld->ld_errno = LDAP_CONTROL_NOT_FOUND; diff --git a/libraries/libldap/ppolicy.c b/libraries/libldap/ppolicy.c index 16193f6400..ad7153406f 100644 --- a/libraries/libldap/ppolicy.c +++ b/libraries/libldap/ppolicy.c @@ -61,22 +61,14 @@ int ldap_create_passwordpolicy_control( LDAP *ld, LDAPControl **ctrlp ) { - BerElement *ber; - assert( ld != NULL ); assert( LDAP_VALID( ld ) ); assert( ctrlp != NULL ); - if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { - ld->ld_errno = LDAP_NO_MEMORY; - return(LDAP_NO_MEMORY); - } - - ld->ld_errno = ldap_create_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, - ber, 0, ctrlp); + ld->ld_errno = ldap_control_create( LDAP_CONTROL_PASSWORDPOLICYREQUEST, + 0, NULL, 0, ctrlp ); - ber_free(ber, 1); - return(ld->ld_errno); + return ld->ld_errno; } @@ -88,8 +80,9 @@ ldap_create_passwordpolicy_control( LDAP *ld, ld (IN) An LDAP session handle. ctrl (IN) The address of an - LDAPControl structure, typically obtained - by a call to ldap_find_control(). + LDAPControl structure, either obtained + by running thorugh the list of response controls or + by a call to ldap_control_find(). exptimep (OUT) This result parameter is filled in with the number of seconds before the password will expire, if expiration is imminent diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index ee0ec5013b..be36b19845 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -255,6 +255,19 @@ ldap_send_server_request( use_connection( ld, lc ); +#ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP( ld )) { + BerElement tmpber = *ber; + ber_rewind( &tmpber ); + rc = ber_write( &tmpber, ld->ld_options.ldo_peer, + sizeof( struct sockaddr ), 0 ); + if ( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return rc; + } + } +#endif + /* If we still have an incomplete write, try to finish it before * dealing with the new request. If we don't finish here, return * LDAP_BUSY and let the caller retry later. We only allow a single @@ -377,11 +390,13 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC ); for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) { - if ( ldap_int_open_connection( ld, lc, *srvp, async) != -1 ) - { + int rc; + + rc = ldap_int_open_connection( ld, lc, *srvp, async ); + if ( rc != -1 ) { srv = *srvp; - if ( ld->ld_urllist_proc ) { + if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) { ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params ); } @@ -465,7 +480,10 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, ++lc->lconn_refcnt; /* avoid premature free */ ld->ld_defconn = lc; - Debug( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_bind_s\n", 0, 0, 0); + Debug( LDAP_DEBUG_TRACE, + "anonymous rebind via ldap_sasl_bind(\"\")\n", + 0, 0, 0); + #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); @@ -503,7 +521,13 @@ ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, break; default: - assert( 0 ); + Debug( LDAP_DEBUG_TRACE, + "ldap_new_connection %p: " + "unexpected response %d " + "from BIND request id=%d\n", + (void *) ld, ldap_msgtype( res ), msgid ); + err = -1; + break; } } } @@ -991,7 +1015,7 @@ ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char * if ( lp == origreq ) { lp = lp->lr_child; } else { - lp = lr->lr_refnext; + lp = lp->lr_refnext; } } if ( looped ) { diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c index 994c52bad7..c492eb9412 100644 --- a/libraries/libldap/result.c +++ b/libraries/libldap/result.c @@ -263,9 +263,8 @@ wait4msg( int rc; struct timeval tv = { 0 }, tv0 = { 0 }, - *tvp; - time_t start_time = 0; - time_t tmp_time; + start_time_tv = { 0 }, + *tvp = NULL; LDAPConn *lc; assert( ld != NULL ); @@ -290,13 +289,16 @@ wait4msg( } #endif /* LDAP_DEBUG */ - if ( timeout == NULL ) { - tvp = NULL; - } else { + if ( timeout != NULL ) { tv0 = *timeout; tv = *timeout; tvp = &tv; - start_time = time( NULL ); +#ifdef HAVE_GETTIMEOFDAY + gettimeofday( &start_time_tv, NULL ); +#else /* ! HAVE_GETTIMEOFDAY */ + time( &start_time_tv.tv_sec ); + start_time_tv.tv_usec = 0; +#endif /* ! HAVE_GETTIMEOFDAY */ } rc = LDAP_MSG_X_KEEP_LOOKING; @@ -423,18 +425,49 @@ wait4msg( } if ( rc == LDAP_MSG_X_KEEP_LOOKING && tvp != NULL ) { - tmp_time = time( NULL ); - tv0.tv_sec -= ( tmp_time - start_time ); - if ( tv0.tv_sec <= 0 ) { - rc = 0; /* timed out */ + struct timeval curr_time_tv = { 0 }, + delta_time_tv = { 0 }; + +#ifdef HAVE_GETTIMEOFDAY + gettimeofday( &curr_time_tv, NULL ); +#else /* ! HAVE_GETTIMEOFDAY */ + time( &curr_time_tv.tv_sec ); + curr_time_tv.tv_usec = 0; +#endif /* ! HAVE_GETTIMEOFDAY */ + + /* delta_time = tmp_time - start_time */ + delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec; + delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec; + if ( delta_time_tv.tv_usec < 0 ) { + delta_time_tv.tv_sec--; + delta_time_tv.tv_usec += 1000000; + } + + /* tv0 < delta_time ? */ + if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) || + ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) ) + { + rc = 0; /* timed out */ ld->ld_errno = LDAP_TIMEOUT; break; } + + /* tv0 -= delta_time */ + tv0.tv_sec -= delta_time_tv.tv_sec; + tv0.tv_usec -= delta_time_tv.tv_usec; + if ( tv0.tv_usec < 0 ) { + tv0.tv_sec--; + tv0.tv_usec += 1000000; + } + tv.tv_sec = tv0.tv_sec; + tv.tv_usec = tv0.tv_usec; + + Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n", + (void *)ld, (long) tv.tv_sec, (long) tv.tv_usec ); - Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld secs to go\n", - (void *)ld, (long) tv.tv_sec, 0 ); - start_time = tmp_time; + start_time_tv.tv_sec = curr_time_tv.tv_sec; + start_time_tv.tv_usec = curr_time_tv.tv_usec; } } diff --git a/libraries/libldap/search.c b/libraries/libldap/search.c index a09b8301ca..2f27eddd6e 100644 --- a/libraries/libldap/search.c +++ b/libraries/libldap/search.c @@ -259,8 +259,9 @@ ldap_build_search_req( LDAP_NEXT_MSGID( ld, *idp ); #ifdef LDAP_CONNECTIONLESS if ( LDAP_IS_UDP(ld) ) { - err = ber_write( ber, ld->ld_options.ldo_peer, - sizeof(struct sockaddr), 0); + struct sockaddr sa = {0}; + /* dummy, filled with ldo_peer in request.c */ + err = ber_write( ber, &sa, sizeof( sa ), 0 ); } if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { char *dn = ld->ld_options.ldo_cldapdn; diff --git a/libraries/libldap/sortctrl.c b/libraries/libldap/sortctrl.c index 0200e01dac..05c66eec09 100644 --- a/libraries/libldap/sortctrl.c +++ b/libraries/libldap/sortctrl.c @@ -408,12 +408,14 @@ ldap_create_sort_control( LDAPControl **ctrlp ) { struct berval value; - BerElement *ber; assert( ld != NULL ); assert( LDAP_VALID( ld ) ); - if ( ld == NULL ) return LDAP_PARAM_ERROR; + if ( ld == NULL ) { + return LDAP_PARAM_ERROR; + } + if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; return ld->ld_errno; @@ -421,19 +423,11 @@ ldap_create_sort_control( ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { - if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { - ld->ld_errno = LDAP_NO_MEMORY; - return LDAP_NO_MEMORY; - } - - ld->ld_errno = ldap_create_control( LDAP_CONTROL_SORTREQUEST, - ber, isCritical, ctrlp ); - if ( ld->ld_errno == LDAP_SUCCESS ) { - (*ctrlp)->ldctl_value = value; - } else { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST, + isCritical, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } - ber_free(ber, 1); } return ld->ld_errno; diff --git a/libraries/libldap/stctrl.c b/libraries/libldap/stctrl.c new file mode 100644 index 0000000000..4dc197cb6c --- /dev/null +++ b/libraries/libldap/stctrl.c @@ -0,0 +1,301 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2007 The OpenLDAP Foundation. + * Portions Copyright 2007 Pierangelo Masarati. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was developed by Pierangelo Masarati for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#include +#include +#include +#include + +#include "ldap-int.h" + +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + +/* + * Client-side of + */ + +int +ldap_create_session_tracking_value( + LDAP *ld, + char *sessionSourceIp, + char *sessionSourceName, + char *formatOID, + struct berval *sessionTrackingIdentifier, + struct berval *value ) +{ + BerElement *ber = NULL; + ber_tag_t tag; + + struct berval ip, name, oid, id; + + if ( ld == NULL || + formatOID == NULL || + value == NULL ) + { +param_error:; + if ( ld ) { + ld->ld_errno = LDAP_PARAM_ERROR; + } + + return LDAP_PARAM_ERROR; + } + + assert( LDAP_VALID( ld ) ); + + /* check sizes according to I.D. */ + if ( sessionSourceIp == NULL ) { + BER_BVSTR( &ip, "" ); + + } else { + ber_str2bv( sessionSourceIp, 0, 0, &ip ); + /* NOTE: we're strict because we don't want + * to send out bad data */ + if ( ip.bv_len > 128 ) goto param_error; + } + + if ( sessionSourceName == NULL ) { + BER_BVSTR( &name, "" ); + + } else { + ber_str2bv( sessionSourceName, 0, 0, &name ); + /* NOTE: we're strict because we don't want + * to send out bad data */ + if ( name.bv_len > 65536 ) goto param_error; + } + + ber_str2bv( formatOID, 0, 0, &oid ); + /* NOTE: we're strict because we don't want + * to send out bad data */ + if ( oid.bv_len > 1024 ) goto param_error; + + if ( sessionTrackingIdentifier == NULL || + sessionTrackingIdentifier->bv_val == NULL ) + { + BER_BVSTR( &id, "" ); + + } else { + id = *sessionTrackingIdentifier; + } + + /* prepare value */ + value->bv_val = NULL; + value->bv_len = 0; + + ber = ldap_alloc_ber_with_options( ld ); + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + tag = ber_printf( ber, "{OOOO}", &ip, &name, &oid, &id ); + if ( tag == LBER_ERROR ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + goto done; + } + + if ( ber_flatten2( ber, value, 1 ) == -1 ) { + ld->ld_errno = LDAP_NO_MEMORY; + } + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + return ld->ld_errno; +} + +/* + * NOTE: this API is bad; it could be much more efficient... + */ +int +ldap_create_session_tracking_control( + LDAP *ld, + char *sessionSourceIp, + char *sessionSourceName, + char *formatOID, + struct berval *sessionTrackingIdentifier, + LDAPControl **ctrlp ) +{ + struct berval value; + + if ( ctrlp == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + ld->ld_errno = ldap_create_session_tracking_value( ld, + sessionSourceIp, sessionSourceName, formatOID, + sessionTrackingIdentifier, &value ); + if ( ld->ld_errno == LDAP_SUCCESS ) { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SESSION_TRACKING, + 0, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { + LDAP_FREE( value.bv_val ); + } + } + + return ld->ld_errno; +} + +int +ldap_parse_session_tracking_control( + LDAP *ld, + LDAPControl *ctrl, + struct berval *ip, + struct berval *name, + struct berval *oid, + struct berval *id ) +{ + BerElement *ber; + ber_tag_t tag; + ber_len_t len; + + if ( ld == NULL || + ctrl == NULL || + ip == NULL || + name == NULL || + oid == NULL || + id == NULL ) + { + if ( ld ) { + ld->ld_errno = LDAP_PARAM_ERROR; + } + + /* NOTE: we want the caller to get all or nothing; + * we could allow some of the pointers to be NULL, + * if one does not want part of the data */ + return LDAP_PARAM_ERROR; + } + + BER_BVZERO( ip ); + BER_BVZERO( name ); + BER_BVZERO( oid ); + BER_BVZERO( id ); + + ber = ber_init( &ctrl->ldctl_value ); + + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_SEQUENCE ) { + tag = LBER_ERROR; + goto error; + } + + /* sessionSourceIp */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else { + if ( len > 128 ) { + /* should be LDAP_DECODING_ERROR, + * but we're liberal in what we accept */ + } + tag = ber_scanf( ber, "o", ip ); + } + + /* sessionSourceName */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else { + if ( len > 65536 ) { + /* should be LDAP_DECODING_ERROR, + * but we're liberal in what we accept */ + } + tag = ber_scanf( ber, "o", name ); + } + + /* formatOID */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + ld->ld_errno = LDAP_DECODING_ERROR; + goto error; + + } else { + if ( len > 1024 ) { + /* should be LDAP_DECODING_ERROR, + * but we're liberal in what we accept */ + } + tag = ber_scanf( ber, "o", oid ); + } + + /* FIXME: should check if it is an OID... leave it to the caller */ + + /* sessionTrackingIdentifier */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else { +#if 0 + if ( len > 65536 ) { + /* should be LDAP_DECODING_ERROR, + * but we're liberal in what we accept */ + } +#endif + tag = ber_scanf( ber, "o", id ); + } + + /* closure */ + tag = ber_skip_tag( ber, &len ); + if ( tag == LBER_DEFAULT && len == 0 ) { + tag = 0; + } + +error:; + (void)ber_free( ber, 1 ); + + if ( tag == LBER_ERROR ) { + return LDAP_DECODING_ERROR; + } + + return ld->ld_errno; +} + +#endif /* LDAP_CONTROL_X_SESSION_TRACKING */ diff --git a/libraries/libldap/test.c b/libraries/libldap/test.c index 7b87e9a90d..b3125301a2 100644 --- a/libraries/libldap/test.c +++ b/libraries/libldap/test.c @@ -277,7 +277,8 @@ main( int argc, char **argv ) char passwd[64], dn[256], rdn[64], attr[64], value[256]; char filter[256], *host, **types; char **exdn; - char *usage = "usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file]\n"; + static const char usage[] = + "usage: %s [-u] [-h host] [-d level] [-s dnsuffix] [-p port] [-t file] [-T file]\n"; int bound, all, scope, attrsonly; LDAPMessage *res; LDAPMod **mods, **attrs; diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index 2d14794a19..8d15e94ead 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -1,4 +1,4 @@ -/* tls.c - Handle tls/ssl using SSLeay or OpenSSL. */ +/* tls.c - Handle tls/ssl using SSLeay, OpenSSL or GNUTLS. */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * @@ -13,6 +13,10 @@ * top-level directory of the distribution or, alternatively, at * . */ +/* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and + * Matt Backes; sponsored by The Written Word (thewrittenword.com) + * and Stanford University (stanford.edu). + */ #include "portable.h" #include "ldap_config.h" @@ -37,6 +41,14 @@ #include #endif +#ifdef HAVE_GNUTLS +#include +#include +#include + +#define DH_BITS (1024) + +#else #ifdef HAVE_OPENSSL_SSL_H #include #include @@ -46,20 +58,320 @@ #elif defined( HAVE_SSL_H ) #include #endif - -static int tls_opt_trace = 1; -static char *tls_opt_randfile = NULL; +#endif #define HAS_TLS( sb ) ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \ (void *)&sb_tls_sbio ) +#endif /* HAVE_TLS */ + +/* RFC2459 minimum required set of supported attribute types + * in a certificate DN + */ +typedef struct oid_name { + struct berval oid; + struct berval name; +} oid_name; + +#define CN_OID oids[0].oid.bv_val + +static oid_name oids[] = { + { BER_BVC("2.5.4.3"), BER_BVC("cn") }, + { BER_BVC("2.5.4.4"), BER_BVC("sn") }, + { BER_BVC("2.5.4.6"), BER_BVC("c") }, + { BER_BVC("2.5.4.7"), BER_BVC("l") }, + { BER_BVC("2.5.4.8"), BER_BVC("st") }, + { BER_BVC("2.5.4.10"), BER_BVC("o") }, + { BER_BVC("2.5.4.11"), BER_BVC("ou") }, + { BER_BVC("2.5.4.12"), BER_BVC("title") }, + { BER_BVC("2.5.4.41"), BER_BVC("name") }, + { BER_BVC("2.5.4.42"), BER_BVC("givenName") }, + { BER_BVC("2.5.4.43"), BER_BVC("initials") }, + { BER_BVC("2.5.4.44"), BER_BVC("generationQualifier") }, + { BER_BVC("2.5.4.46"), BER_BVC("dnQualifier") }, + { BER_BVC("1.2.840.113549.1.9.1"), BER_BVC("email") }, + { BER_BVC("0.9.2342.19200300.100.1.25"), BER_BVC("dc") }, + { BER_BVNULL, BER_BVNULL } +}; + +#ifdef HAVE_TLS +#ifdef HAVE_GNUTLS + +typedef struct tls_cipher_suite { + const char *name; + gnutls_kx_algorithm_t kx; + gnutls_cipher_algorithm_t cipher; + gnutls_mac_algorithm_t mac; + gnutls_protocol_t version; +} tls_cipher_suite; + +static tls_cipher_suite *ciphers; +static int n_ciphers; + +/* sorta replacing SSL_CTX */ +typedef struct tls_ctx { + struct ldapoptions *lo; + gnutls_certificate_credentials_t cred; + gnutls_dh_params_t dh_params; + unsigned long verify_depth; + int refcount; + int *kx_list; + int *cipher_list; + int *mac_list; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_t ref_mutex; +#endif +} tls_ctx; + +/* sorta replacing SSL */ +typedef struct tls_session { + tls_ctx *ctx; + gnutls_session_t session; + struct berval peer_der_dn; +} tls_session; + +#ifdef LDAP_R_COMPILE + +static int +ldap_pvt_gcry_mutex_init( void **priv ) +{ + int err = 0; + ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t )); + + if ( !lock ) + err = ENOMEM; + if ( !err ) { + err = ldap_pvt_thread_mutex_init( lock ); + if ( err ) + LDAP_FREE( lock ); + else + *priv = lock; + } + return err; +} +static int +ldap_pvt_gcry_mutex_destroy( void **lock ) +{ + int err = ldap_pvt_thread_mutex_destroy( *lock ); + LDAP_FREE( *lock ); + return err; +} +static int +ldap_pvt_gcry_mutex_lock( void **lock ) +{ + return ldap_pvt_thread_mutex_lock( *lock ); +} +static int +ldap_pvt_gcry_mutex_unlock( void **lock ) +{ + return ldap_pvt_thread_mutex_unlock( *lock ); +} + +static struct gcry_thread_cbs ldap_generic_thread_cbs = { + GCRY_THREAD_OPTION_USER, + NULL, + ldap_pvt_gcry_mutex_init, + ldap_pvt_gcry_mutex_destroy, + ldap_pvt_gcry_mutex_lock, + ldap_pvt_gcry_mutex_unlock, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +static void +tls_init_threads( void ) +{ + gcry_control (GCRYCTL_SET_THREAD_CBS, &ldap_generic_thread_cbs); +} +#endif /* LDAP_R_COMPILE */ + +void +ldap_pvt_tls_ctx_free ( void *c ) +{ + int refcount; + tls_ctx *ctx = c; + + if ( !ctx ) return; + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ctx->ref_mutex ); +#endif + refcount = --ctx->refcount; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex ); +#endif + if ( refcount ) + return; + LDAP_FREE( ctx->kx_list ); + gnutls_certificate_free_credentials( ctx->cred ); + ber_memfree ( ctx ); +} + +static void * +tls_ctx_new ( struct ldapoptions *lo ) +{ + tls_ctx *ctx; + + ctx = ber_memcalloc ( 1, sizeof (*ctx) ); + if ( ctx ) { + ctx->lo = lo; + if ( gnutls_certificate_allocate_credentials( &ctx->cred )) { + ber_memfree( ctx ); + return NULL; + } + ctx->refcount = 1; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_init( &ctx->ref_mutex ); +#endif + } + return ctx; +} + +static void +tls_ctx_ref( tls_ctx *ctx ) +{ +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ctx->ref_mutex ); +#endif + ctx->refcount++; +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ctx->ref_mutex ); +#endif +} + +tls_session * +tls_session_new ( tls_ctx * ctx, int is_server ) +{ + tls_session *session; + + session = ber_memcalloc ( 1, sizeof (*session) ); + if ( !session ) + return NULL; + + session->ctx = ctx; + gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT ); + gnutls_set_default_priority( session->session ); + if ( ctx->kx_list ) { + gnutls_kx_set_priority( session->session, ctx->kx_list ); + gnutls_cipher_set_priority( session->session, ctx->cipher_list ); + gnutls_mac_set_priority( session->session, ctx->mac_list ); + } + if ( ctx->cred ) + gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, ctx->cred ); + + if ( is_server ) { + int flag = 0; + if ( ctx->lo->ldo_tls_require_cert ) { + flag = GNUTLS_CERT_REQUEST; + if ( ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || + ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) + flag = GNUTLS_CERT_REQUIRE; + gnutls_certificate_server_set_request( session->session, flag ); + } + } + return session; +} + +void +tls_session_free ( tls_session * session ) +{ + ber_memfree ( session ); +} + +#define tls_session_connect( ssl ) gnutls_handshake( ssl->session ) +#define tls_session_accept( ssl ) gnutls_handshake( ssl->session ) + +/* suites is a string of colon-separated cipher suite names. */ +static int +tls_parse_ciphers( tls_ctx *ctx, char *suites ) +{ + char *ptr, *end; + int i, j, len, num; + int *list, nkx = 0, ncipher = 0, nmac = 0; + int *kx, *cipher, *mac; + + num = 0; + ptr = suites; + do { + end = strchr(ptr, ':'); + if ( end ) + len = end - ptr; + else + len = strlen(ptr); + for (i=0; ikx_list = kx; + ctx->cipher_list = cipher; + ctx->mac_list = mac; + return 0; +} + +#else /* OpenSSL */ + +typedef SSL_CTX tls_ctx; +typedef SSL tls_session; + +static int tls_opt_trace = 1; +static char *tls_opt_randfile = NULL; + static void tls_report_error( void ); static void tls_info_cb( const SSL *ssl, int where, int ret ); static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ); static int tls_verify_ok( int ok, X509_STORE_CTX *ctx ); static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); -static STACK_OF(X509_NAME) * get_ca_list( char * bundle, char * dir ); static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ); @@ -88,12 +400,18 @@ static void tls_locking_cb( int mode, int type, const char *file, int line ) } } -/* - * an extra mutex for the default ctx. - */ +static unsigned long tls_thread_self( void ) +{ + /* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t + * is an integral type that fits in an unsigned long + */ -static ldap_pvt_thread_mutex_t tls_def_ctx_mutex; -static ldap_pvt_thread_mutex_t tls_connect_mutex; + /* force an error if the ldap_pvt_thread_t type is too large */ + enum { ok = sizeof( ldap_pvt_thread_t ) <= sizeof( unsigned long ) }; + typedef struct { int dummy: ok ? 1 : -1; } Check[ok ? 1 : -1]; + + return (unsigned long) ldap_pvt_thread_self(); +} static void tls_init_threads( void ) { @@ -103,21 +421,79 @@ static void tls_init_threads( void ) ldap_pvt_thread_mutex_init( &tls_mutexes[i] ); } CRYPTO_set_locking_callback( tls_locking_cb ); - CRYPTO_set_id_callback( ldap_pvt_thread_self ); - /* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t - * is an integral type that fits in an unsigned long - */ - - ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex ); - ldap_pvt_thread_mutex_init( &tls_connect_mutex ); + CRYPTO_set_id_callback( tls_thread_self ); } #endif /* LDAP_R_COMPILE */ +void +ldap_pvt_tls_ctx_free ( void *c ) +{ + + SSL_CTX_free( c ); +} + +static void * +tls_ctx_new( struct ldapoptions *lo ) +{ + return SSL_CTX_new( SSLv23_method() ); +} + +static void +tls_ctx_ref( void *c ) +{ + SSL_CTX *ctx = c; + CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX ); +} + +static tls_session * +tls_session_new( tls_ctx *ctx, int is_server ) +{ + return SSL_new( ctx ); +} + +#define tls_session_connect( ssl ) SSL_connect( ssl ) +#define tls_session_accept( ssl ) SSL_accept( ssl ) + +static STACK_OF(X509_NAME) * +get_ca_list( char * bundle, char * dir ) +{ + STACK_OF(X509_NAME) *ca_list = NULL; + + if ( bundle ) { + ca_list = SSL_load_client_CA_file( bundle ); + } +#if defined(HAVE_DIRENT_H) || defined(dirent) + if ( dir ) { + int freeit = 0; + + if ( !ca_list ) { + ca_list = sk_X509_NAME_new_null(); + freeit = 1; + } + if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) && + freeit ) { + sk_X509_NAME_free( ca_list ); + ca_list = NULL; + } + } +#endif + return ca_list; +} + +#endif /* HAVE_GNUTLS */ + +#ifdef LDAP_R_COMPILE +/* + * an extra mutex for the default ctx. + */ +static ldap_pvt_thread_mutex_t tls_def_ctx_mutex; +#endif + void ldap_int_tls_destroy( struct ldapoptions *lo ) { if ( lo->ldo_tls_ctx ) { - SSL_CTX_free( lo->ldo_tls_ctx ); + ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; } @@ -145,6 +521,12 @@ ldap_int_tls_destroy( struct ldapoptions *lo ) LDAP_FREE( lo->ldo_tls_ciphersuite ); lo->ldo_tls_ciphersuite = NULL; } +#ifdef HAVE_GNUTLS + if ( lo->ldo_tls_crlfile ) { + LDAP_FREE( lo->ldo_tls_crlfile ); + lo->ldo_tls_crlfile = NULL; + } +#endif } /* @@ -157,6 +539,12 @@ ldap_pvt_tls_destroy( void ) ldap_int_tls_destroy( lo ); +#ifdef HAVE_GNUTLS + LDAP_FREE( ciphers ); + ciphers = NULL; + + gnutls_global_deinit(); +#else EVP_cleanup(); ERR_remove_state(0); ERR_free_strings(); @@ -165,6 +553,7 @@ ldap_pvt_tls_destroy( void ) LDAP_FREE( tls_opt_randfile ); tls_opt_randfile = NULL; } +#endif } /* @@ -177,6 +566,43 @@ ldap_pvt_tls_init( void ) if ( tls_initialized++ ) return 0; +#ifdef LDAP_R_COMPILE + tls_init_threads(); + ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex ); +#endif + +#ifdef HAVE_GNUTLS + gnutls_global_init (); + + /* GNUtls cipher suite handling: The library ought to parse suite + * names for us, but it doesn't. It will return a list of suite names + * that it supports, so we can do parsing ourselves. It ought to tell + * us how long the list is, but it doesn't do that either, so we just + * have to count it manually... + */ + { + int i = 0; + tls_cipher_suite *ptr, tmp; + char cs_id[2]; + + while ( gnutls_cipher_suite_info( i, cs_id, &tmp.kx, &tmp.cipher, + &tmp.mac, &tmp.version )) + i++; + n_ciphers = i; + + /* Store a copy */ + ciphers = LDAP_MALLOC(n_ciphers * sizeof(tls_cipher_suite)); + if ( !ciphers ) + return -1; + for ( i=0; ildo_tls_ciphersuite; char *cacertfile = lo->ldo_tls_cacertfile; char *cacertdir = lo->ldo_tls_cacertdir; char *certfile = lo->ldo_tls_certfile; char *keyfile = lo->ldo_tls_keyfile; +#ifdef HAVE_GNUTLS + char *crlfile = lo->ldo_tls_crlfile; +#else char *dhfile = lo->ldo_tls_dhfile; +#endif if ( lo->ldo_tls_ctx ) return 0; @@ -235,10 +662,6 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) cacertfile = LDAP_STRDUP( cacertfile ); __atoe( cacertfile ); } - if ( cacertdir ) { - cacertdir = LDAP_STRDUP( cacertdir ); - __atoe( cacertdir ); - } if ( certfile ) { certfile = LDAP_STRDUP( certfile ); __atoe( certfile ); @@ -247,20 +670,100 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) keyfile = LDAP_STRDUP( keyfile ); __atoe( keyfile ); } +#ifdef HAVE_GNUTLS + if ( crlfile ) { + crlfile = LDAP_STRDUP( crlfile ); + __atoe( crlfile ); + } +#else + if ( cacertdir ) { + cacertdir = LDAP_STRDUP( cacertdir ); + __atoe( cacertdir ); + } if ( dhfile ) { dhfile = LDAP_STRDUP( dhfile ); __atoe( dhfile ); } #endif - lo->ldo_tls_ctx = SSL_CTX_new( SSLv23_method() ); +#endif + lo->ldo_tls_ctx = tls_ctx_new( lo ); if ( lo->ldo_tls_ctx == NULL ) { +#ifdef HAVE_GNUTLS + Debug( LDAP_DEBUG_ANY, + "TLS: could not allocate default ctx.\n", + 0,0,0); +#else Debug( LDAP_DEBUG_ANY, "TLS: could not allocate default ctx (%lu).\n", ERR_peek_error(),0,0); +#endif rc = -1; goto error_exit; } +#ifdef HAVE_GNUTLS + if ( lo->ldo_tls_ciphersuite && + tls_parse_ciphers( lo->ldo_tls_ctx, + ciphersuite )) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not set cipher list %s.\n", + lo->ldo_tls_ciphersuite, 0, 0 ); + rc = -1; + goto error_exit; + } + + if (lo->ldo_tls_cacertdir != NULL) { + Debug( LDAP_DEBUG_ANY, + "TLS: warning: cacertdir not implemented for gnutls\n", + NULL, NULL, NULL ); + } + + if (lo->ldo_tls_cacertfile != NULL) { + rc = gnutls_certificate_set_x509_trust_file( + ((tls_ctx*) lo->ldo_tls_ctx)->cred, + cacertfile, + GNUTLS_X509_FMT_PEM ); + if ( rc < 0 ) goto error_exit; + } + + if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) { + rc = gnutls_certificate_set_x509_key_file( + ((tls_ctx*) lo->ldo_tls_ctx)->cred, + certfile, + keyfile, + GNUTLS_X509_FMT_PEM ); + if ( rc ) goto error_exit; + } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) { + Debug( LDAP_DEBUG_ANY, + "TLS: only one of certfile and keyfile specified\n", + NULL, NULL, NULL ); + rc = 1; + goto error_exit; + } + + if ( lo->ldo_tls_dhfile ) { + Debug( LDAP_DEBUG_ANY, + "TLS: warning: ignoring dhfile\n", + NULL, NULL, NULL ); + } + + if ( lo->ldo_tls_crlfile ) { + rc = gnutls_certificate_set_x509_crl_file( + ((tls_ctx*) lo->ldo_tls_ctx)->cred, + crlfile, + GNUTLS_X509_FMT_PEM ); + if ( rc < 0 ) goto error_exit; + } + if ( is_server ) { + gnutls_dh_params_init (&((tls_ctx*) + lo->ldo_tls_ctx)->dh_params); + gnutls_dh_params_generate2 (((tls_ctx*) + lo->ldo_tls_ctx)->dh_params, + DH_BITS); + } + +#else /* !HAVE_GNUTLS */ + if ( is_server ) { SSL_CTX_set_session_id_context( lo->ldo_tls_ctx, (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 ); @@ -293,6 +796,7 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) } if ( is_server ) { + STACK_OF(X509_NAME) *calist; /* List of CA names to send to a client */ calist = get_ca_list( cacertfile, cacertdir ); if ( !calist ) { @@ -392,18 +896,24 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) } #endif +#endif /* HAVE_GNUTLS */ + error_exit: if ( rc == -1 && lo->ldo_tls_ctx != NULL ) { - SSL_CTX_free( lo->ldo_tls_ctx ); + ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; } #ifdef HAVE_EBCDIC LDAP_FREE( ciphersuite ); LDAP_FREE( cacertfile ); - LDAP_FREE( cacertdir ); LDAP_FREE( certfile ); LDAP_FREE( keyfile ); +#ifdef HAVE_GNUTLS + LDAP_FREE( crlfile ); +#else + LDAP_FREE( cacertdir ); LDAP_FREE( dhfile ); +#endif #endif return rc; } @@ -426,47 +936,21 @@ ldap_pvt_tls_init_def_ctx( int is_server ) return rc; } -static STACK_OF(X509_NAME) * -get_ca_list( char * bundle, char * dir ) -{ - STACK_OF(X509_NAME) *ca_list = NULL; - - if ( bundle ) { - ca_list = SSL_load_client_CA_file( bundle ); - } -#if defined(HAVE_DIRENT_H) || defined(dirent) - if ( dir ) { - int freeit = 0; - - if ( !ca_list ) { - ca_list = sk_X509_NAME_new_null(); - freeit = 1; - } - if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) && - freeit ) { - sk_X509_NAME_free( ca_list ); - ca_list = NULL; - } - } -#endif - return ca_list; -} - -static SSL * +static tls_session * alloc_handle( void *ctx_arg, int is_server ) { - SSL_CTX *ctx; - SSL *ssl; + tls_ctx *ctx; + tls_session *ssl; if ( ctx_arg ) { - ctx = (SSL_CTX *) ctx_arg; + ctx = ctx_arg; } else { struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL; ctx = lo->ldo_tls_ctx; } - ssl = SSL_new( ctx ); + ssl = tls_session_new( ctx, is_server ); if ( ssl == NULL ) { Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0); return NULL; @@ -475,24 +959,37 @@ alloc_handle( void *ctx_arg, int is_server ) } static int -update_flags( Sockbuf *sb, SSL * ssl, int rc ) +update_flags( Sockbuf *sb, tls_session * ssl, int rc ) { - int err = SSL_get_error(ssl, rc); - sb->sb_trans_needs_read = 0; sb->sb_trans_needs_write = 0; - if (err == SSL_ERROR_WANT_READ) { +#ifdef HAVE_GNUTLS + if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN ) + return 0; + + switch (gnutls_record_get_direction (ssl->session)) { + case 0: + sb->sb_trans_needs_read = 1; + return 1; + case 1: + sb->sb_trans_needs_write = 1; + return 1; + } +#else /* !HAVE_GNUTLS */ + rc = SSL_get_error(ssl, rc); + if (rc == SSL_ERROR_WANT_READ) { sb->sb_trans_needs_read = 1; return 1; - } else if (err == SSL_ERROR_WANT_WRITE) { + } else if (rc == SSL_ERROR_WANT_WRITE) { sb->sb_trans_needs_write = 1; return 1; - } else if (err == SSL_ERROR_WANT_CONNECT) { + } else if (rc == SSL_ERROR_WANT_CONNECT) { return 1; } +#endif /* HAVE_GNUTLS */ return 0; } @@ -501,17 +998,49 @@ update_flags( Sockbuf *sb, SSL * ssl, int rc ) */ struct tls_data { - SSL *ssl; + tls_session *ssl; Sockbuf_IO_Desc *sbiod; }; -static BIO_METHOD sb_tls_bio_method; +#ifdef HAVE_GNUTLS + +static ssize_t +sb_gtls_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len ) +{ + struct tls_data *p; + + if ( buf == NULL || len <= 0 ) return 0; + + p = (struct tls_data *)ptr; + + if ( p == NULL || p->sbiod == NULL ) { + return 0; + } + + return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); +} + +static ssize_t +sb_gtls_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len ) +{ + struct tls_data *p; + + if ( buf == NULL || len <= 0 ) return 0; + + p = (struct tls_data *)ptr; + + if ( p == NULL || p->sbiod == NULL ) { + return 0; + } + + return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); +} static int sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg ) { struct tls_data *p; - BIO *bio; + tls_session *session = arg; assert( sbiod != NULL ); @@ -520,11 +1049,11 @@ sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg ) return -1; } - p->ssl = (SSL *)arg; + gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p ); + gnutls_transport_set_pull_function( session->session, sb_gtls_recv ); + gnutls_transport_set_push_function( session->session, sb_gtls_send ); + p->ssl = arg; p->sbiod = sbiod; - bio = BIO_new( &sb_tls_bio_method ); - bio->ptr = (void *)p; - SSL_set_bio( p->ssl, bio, bio ); sbiod->sbiod_pvt = p; return 0; } @@ -538,7 +1067,8 @@ sb_tls_remove( Sockbuf_IO_Desc *sbiod ) assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; - SSL_free( p->ssl ); + gnutls_deinit ( p->ssl->session ); + LBER_FREE( p->ssl ); LBER_FREE( sbiod->sbiod_pvt ); sbiod->sbiod_pvt = NULL; return 0; @@ -553,7 +1083,7 @@ sb_tls_close( Sockbuf_IO_Desc *sbiod ) assert( sbiod->sbiod_pvt != NULL ); p = (struct tls_data *)sbiod->sbiod_pvt; - SSL_shutdown( p->ssl ); + gnutls_bye ( p->ssl->session, GNUTLS_SHUT_RDWR ); return 0; } @@ -568,11 +1098,11 @@ sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) p = (struct tls_data *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_GET_SSL ) { - *((SSL **)arg) = p->ssl; + *((tls_session **)arg) = p->ssl; return 1; - + } else if ( opt == LBER_SB_OPT_DATA_READY ) { - if( SSL_pending( p->ssl ) > 0 ) { + if( gnutls_record_check_pending( p->ssl->session ) > 0 ) { return 1; } } @@ -592,17 +1122,24 @@ sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) p = (struct tls_data *)sbiod->sbiod_pvt; - ret = SSL_read( p->ssl, (char *)buf, len ); -#ifdef HAVE_WINSOCK - errno = WSAGetLastError(); -#endif - err = SSL_get_error( p->ssl, ret ); - if (err == SSL_ERROR_WANT_READ ) { + ret = gnutls_record_recv ( p->ssl->session, buf, len ); + switch (ret) { + case GNUTLS_E_INTERRUPTED: + case GNUTLS_E_AGAIN: sbiod->sbiod_sb->sb_trans_needs_read = 1; sock_errset(EWOULDBLOCK); - } - else + ret = 0; + break; + case GNUTLS_E_REHANDSHAKE: + for ( ret = gnutls_handshake ( p->ssl->session ); + ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN; + ret = gnutls_handshake ( p->ssl->session ) ); + sbiod->sbiod_sb->sb_trans_needs_read = 1; + ret = 0; + break; + default: sbiod->sbiod_sb->sb_trans_needs_read = 0; + } return ret; } @@ -618,30 +1155,19 @@ sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) p = (struct tls_data *)sbiod->sbiod_pvt; - ret = SSL_write( p->ssl, (char *)buf, len ); -#ifdef HAVE_WINSOCK - errno = WSAGetLastError(); -#endif - err = SSL_get_error( p->ssl, ret ); - if (err == SSL_ERROR_WANT_WRITE ) { + ret = gnutls_record_send ( p->ssl->session, (char *)buf, len ); + + if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) { sbiod->sbiod_sb->sb_trans_needs_write = 1; sock_errset(EWOULDBLOCK); - + ret = 0; } else { sbiod->sbiod_sb->sb_trans_needs_write = 0; } return ret; } -static Sockbuf_IO sb_tls_sbio = -{ - sb_tls_setup, /* sbi_setup */ - sb_tls_remove, /* sbi_remove */ - sb_tls_ctrl, /* sbi_ctrl */ - sb_tls_read, /* sbi_read */ - sb_tls_write, /* sbi_write */ - sb_tls_close /* sbi_close */ -}; +#else /* !HAVE_GNUTLS */ static int sb_tls_bio_create( BIO *b ) { @@ -734,23 +1260,195 @@ sb_tls_bio_gets( BIO *b, char *buf, int len ) } static int -sb_tls_bio_puts( BIO *b, const char *str ) +sb_tls_bio_puts( BIO *b, const char *str ) +{ + return sb_tls_bio_write( b, str, strlen( str ) ); +} + +static BIO_METHOD sb_tls_bio_method = +{ + ( 100 | 0x400 ), /* it's a source/sink BIO */ + "sockbuf glue", + sb_tls_bio_write, + sb_tls_bio_read, + sb_tls_bio_puts, + sb_tls_bio_gets, + sb_tls_bio_ctrl, + sb_tls_bio_create, + sb_tls_bio_destroy +}; + +static int +sb_tls_setup( Sockbuf_IO_Desc *sbiod, void *arg ) +{ + struct tls_data *p; + BIO *bio; + + assert( sbiod != NULL ); + + p = LBER_MALLOC( sizeof( *p ) ); + if ( p == NULL ) { + return -1; + } + + p->ssl = (SSL *)arg; + p->sbiod = sbiod; + bio = BIO_new( &sb_tls_bio_method ); + bio->ptr = (void *)p; + SSL_set_bio( p->ssl, bio, bio ); + sbiod->sbiod_pvt = p; + return 0; +} + +static int +sb_tls_remove( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_free( p->ssl ); + LBER_FREE( sbiod->sbiod_pvt ); + sbiod->sbiod_pvt = NULL; + return 0; +} + +static int +sb_tls_close( Sockbuf_IO_Desc *sbiod ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + SSL_shutdown( p->ssl ); + return 0; +} + +static int +sb_tls_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) +{ + struct tls_data *p; + + assert( sbiod != NULL ); + assert( sbiod->sbiod_pvt != NULL ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + if ( opt == LBER_SB_OPT_GET_SSL ) { + *((SSL **)arg) = p->ssl; + return 1; + + } else if ( opt == LBER_SB_OPT_DATA_READY ) { + if( SSL_pending( p->ssl ) > 0 ) { + return 1; + } + } + + return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); +} + +static ber_slen_t +sb_tls_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_read( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_READ ) { + sbiod->sbiod_sb->sb_trans_needs_read = 1; + sock_errset(EWOULDBLOCK); + } + else + sbiod->sbiod_sb->sb_trans_needs_read = 0; + return ret; +} + +static ber_slen_t +sb_tls_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) +{ + struct tls_data *p; + ber_slen_t ret; + int err; + + assert( sbiod != NULL ); + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + + p = (struct tls_data *)sbiod->sbiod_pvt; + + ret = SSL_write( p->ssl, (char *)buf, len ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif + err = SSL_get_error( p->ssl, ret ); + if (err == SSL_ERROR_WANT_WRITE ) { + sbiod->sbiod_sb->sb_trans_needs_write = 1; + sock_errset(EWOULDBLOCK); + + } else { + sbiod->sbiod_sb->sb_trans_needs_write = 0; + } + return ret; +} + +#endif + +static Sockbuf_IO sb_tls_sbio = +{ + sb_tls_setup, /* sbi_setup */ + sb_tls_remove, /* sbi_remove */ + sb_tls_ctrl, /* sbi_ctrl */ + sb_tls_read, /* sbi_read */ + sb_tls_write, /* sbi_write */ + sb_tls_close /* sbi_close */ +}; + +#ifdef HAVE_GNUTLS +/* Certs are not automatically varified during the handshake */ +static int +tls_cert_verify( tls_session *ssl ) { - return sb_tls_bio_write( b, str, strlen( str ) ); + unsigned int status = 0; + int err; + time_t now = time(0); + + err = gnutls_certificate_verify_peers2( ssl->session, &status ); + if ( err < 0 ) { + Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n", + err,0,0 ); + return -1; + } + if ( status ) { + Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n", + status, 0,0 ); + return -1; + } + if ( gnutls_certificate_expiration_time_peers( ssl->session ) < now ) { + Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n", + 0, 0, 0 ); + return -1; + } + if ( gnutls_certificate_activation_time_peers( ssl->session ) > now ) { + Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n", + 0, 0, 0 ); + return -1; + } + return 0; } - -static BIO_METHOD sb_tls_bio_method = -{ - ( 100 | 0x400 ), /* it's a source/sink BIO */ - "sockbuf glue", - sb_tls_bio_write, - sb_tls_bio_read, - sb_tls_bio_puts, - sb_tls_bio_gets, - sb_tls_bio_ctrl, - sb_tls_bio_create, - sb_tls_bio_destroy -}; +#endif /* HAVE_GNUTLS */ /* * Call this to do a TLS connect on a sockbuf. ctx_arg can be @@ -770,14 +1468,14 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) { Sockbuf *sb = conn->lconn_sb; int err; - SSL *ssl; + tls_session *ssl; if ( HAS_TLS( sb ) ) { ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); } else { struct ldapoptions *lo; - SSL_CTX *ctx; + tls_ctx *ctx; ctx = ld->ld_options.ldo_tls_ctx; @@ -796,7 +1494,7 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) if( ctx == NULL ) { ctx = lo->ldo_tls_ctx; ld->ld_options.ldo_tls_ctx = ctx; - CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX ); + tls_ctx_ref( ctx ); } if ( ld->ld_options.ldo_tls_connect_cb ) ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx, @@ -806,24 +1504,37 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg ); } - err = SSL_connect( ssl ); + err = tls_session_connect( ssl ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif - if ( err <= 0 ) { +#ifdef HAVE_GNUTLS + if ( err < 0 ) +#else + if ( err <= 0 ) +#endif + { if ( update_flags( sb, ssl, err )) { return 1; } - if ((err = ERR_peek_error())) { - char buf[256]; - +#ifndef HAVE_GNUTLS + if ((err = ERR_peek_error())) +#endif + { if ( ld->ld_error ) { LDAP_FREE( ld->ld_error ); } - ld->ld_error = LDAP_STRDUP(ERR_error_string(err, buf)); +#ifdef HAVE_GNUTLS + ld->ld_error = LDAP_STRDUP(gnutls_strerror( err )); +#else + { + char buf[256]; + ld->ld_error = LDAP_STRDUP(ERR_error_string(err, buf)); + } +#endif #ifdef HAVE_EBCDIC if ( ld->ld_error ) __etoa(ld->ld_error); #endif @@ -841,6 +1552,14 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) return -1; } +#ifdef HAVE_GNUTLS + if ( ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) { + err = tls_cert_verify( ssl ); + if ( err && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW ) + return err; + } +#endif + return 0; } @@ -852,7 +1571,7 @@ int ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) { int err; - SSL *ssl; + tls_session *ssl; if ( HAS_TLS( sb ) ) { ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl ); @@ -869,23 +1588,27 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl ); } -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_lock( &tls_connect_mutex ); -#endif - err = SSL_accept( ssl ); -#ifdef LDAP_R_COMPILE - ldap_pvt_thread_mutex_unlock( &tls_connect_mutex ); -#endif + err = tls_session_accept( ssl ); #ifdef HAVE_WINSOCK errno = WSAGetLastError(); #endif - if ( err <= 0 ) { + +#ifdef HAVE_GNUTLS + if ( err < 0 ) +#else + if ( err <= 0 ) +#endif + { if ( update_flags( sb, ssl, err )) return 1; +#ifdef HAVE_GNUTLS + Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n", + gnutls_strerror( err ),0,0 ); +#else Debug( LDAP_DEBUG_ANY,"TLS: can't accept.\n",0,0,0 ); - tls_report_error(); +#endif ber_sockbuf_remove_io( sb, &sb_tls_sbio, LBER_SBIOD_LEVEL_TRANSPORT ); #ifdef LDAP_DEBUG @@ -895,6 +1618,13 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) return -1; } +#ifdef HAVE_GNUTLS + if ( ssl->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) { + err = tls_cert_verify( ssl ); + if ( err && ssl->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW ) + return err; + } +#endif return 0; } @@ -922,6 +1652,60 @@ ldap_tls_inplace( LDAP *ld ) return ldap_pvt_tls_inplace( sb ); } +#ifdef HAVE_GNUTLS +static void +x509_cert_get_dn( struct berval *cert, struct berval *dn, int get_subject ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + ber_len_t len; + ber_int_t i; + + ber_init2( ber, cert, LBER_USE_DER ); + tag = ber_skip_tag( ber, &len ); /* Sequence */ + tag = ber_skip_tag( ber, &len ); /* Sequence */ + tag = ber_skip_tag( ber, &len ); /* Context + Constructed (version) */ + if ( tag == 0xa0 ) /* Version is optional */ + tag = ber_get_int( ber, &i ); /* Int: Version */ + tag = ber_get_int( ber, &i ); /* Int: Serial */ + tag = ber_skip_tag( ber, &len ); /* Sequence: Signature */ + ber_skip_data( ber, len ); + if ( !get_subject ) { + tag = ber_peek_tag( ber, &len ); /* Sequence: Issuer DN */ + } else { + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* Sequence: Validity */ + ber_skip_data( ber, len ); + tag = ber_peek_tag( ber, &len ); /* Sequence: Subject DN */ + } + len = ber_ptrlen( ber ); + dn->bv_val = cert->bv_val + len; + dn->bv_len = cert->bv_len - len; +} + +static int +tls_get_cert_dn( tls_session *session, struct berval *dnbv ) +{ + if ( !session->peer_der_dn.bv_val ) { + const gnutls_datum_t *peer_cert_list; + int list_size; + struct berval bv; + + peer_cert_list = gnutls_certificate_get_peers( session->session, + &list_size ); + if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS; + + bv.bv_len = peer_cert_list->size; + bv.bv_val = peer_cert_list->data; + + x509_cert_get_dn( &bv, &session->peer_der_dn, 1 ); + *dnbv = session->peer_der_dn; + } + return 0; +} +#else /* !HAVE_GNUTLS */ static X509 * tls_get_cert( SSL *s ) { @@ -936,52 +1720,207 @@ tls_get_cert( SSL *s ) return SSL_get_peer_certificate(s); } +static int +tls_get_cert_dn( tls_session *session, struct berval *dnbv ) +{ + X509_NAME *xn; + X509 *x = tls_get_cert( session ); + + if ( !x ) + return LDAP_INVALID_CREDENTIALS; + + xn = X509_get_subject_name(x); + dnbv->bv_len = i2d_X509_NAME( xn, NULL ); + dnbv->bv_val = xn->bytes->data; + return 0; +} +#endif /* HAVE_GNUTLS */ + int ldap_pvt_tls_get_peer_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags ) { - X509 *x; - X509_NAME *xn; + tls_session *session = s; + struct berval bvdn; int rc; - x = tls_get_cert((SSL *)s); + rc = tls_get_cert_dn( session, &bvdn ); + if ( rc ) return rc; - if (!x) return LDAP_INVALID_CREDENTIALS; - - xn = X509_get_subject_name(x); - rc = ldap_X509dn2bv(xn, dn, (LDAPDN_rewrite_func *)func, flags); - X509_free(x); + rc = ldap_X509dn2bv( &bvdn, dn, + (LDAPDN_rewrite_func *)func, flags); return rc; } -char * -ldap_pvt_tls_get_peer_hostname( void *s ) +/* what kind of hostname were we given? */ +#define IS_DNS 0 +#define IS_IP4 1 +#define IS_IP6 2 + +#ifdef HAVE_GNUTLS + +int +ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) { - X509 *x; - X509_NAME *xn; - char buf[2048], *p; - int ret; + tls_session *session = s; + int i, ret; + const gnutls_datum_t *peer_cert_list; + int list_size; + struct berval bv; + char altname[NI_MAXHOST]; + size_t altnamesize; + + gnutls_x509_crt_t cert; + gnutls_datum_t *x; + const char *name; + char *ptr; + char *domain = NULL; +#ifdef LDAP_PF_INET6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + int n, len1 = 0, len2 = 0; + int ntype = IS_DNS; + time_t now = time(0); - x = tls_get_cert((SSL *)s); - if (!x) return NULL; + if( ldap_int_hostname && + ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) + { + name = ldap_int_hostname; + } else { + name = name_in; + } + + peer_cert_list = gnutls_certificate_get_peers( session->session, + &list_size ); + if ( !peer_cert_list ) { + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get peer certificate.\n", + 0, 0, 0 ); + /* If this was a fatal condition, things would have + * aborted long before now. + */ + return LDAP_SUCCESS; + } + ret = gnutls_x509_crt_init( &cert ); + if ( ret < 0 ) + return LDAP_LOCAL_ERROR; + ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER ); + if ( ret ) { + gnutls_x509_crt_deinit( cert ); + return LDAP_LOCAL_ERROR; + } + +#ifdef LDAP_PF_INET6 + if (name[0] == '[' && strchr(name, ']')) { + char *n2 = ldap_strdup(name+1); + *strchr(n2, ']') = 2; + if (inet_pton(AF_INET6, n2, &addr)) + ntype = IS_IP6; + LDAP_FREE(n2); + } else +#endif + if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { + if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; + } - xn = X509_get_subject_name(x); + if (ntype == IS_DNS) { + len1 = strlen(name); + domain = strchr(name, '.'); + if (domain) { + len2 = len1 - (domain-name); + } + } - ret = X509_NAME_get_text_by_NID(xn, NID_commonName, buf, sizeof(buf)); - if( ret == -1 ) { - X509_free(x); - return NULL; + for ( i=0, ret=0; ret >= 0; i++ ) { + altnamesize = sizeof(altname); + ret = gnutls_x509_crt_get_subject_alt_name( cert, i, + altname, &altnamesize, NULL ); + if ( ret < 0 ) break; + + /* ignore empty */ + if ( altnamesize == 0 ) continue; + + if ( ret == GNUTLS_SAN_DNSNAME ) { + if (ntype != IS_DNS) continue; + + /* Is this an exact match? */ + if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) { + break; + } + + /* Is this a wildcard match? */ + if (domain && (altname[0] == '*') && (altname[1] == '.') && + (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) + { + break; + } + } else if ( ret == GNUTLS_SAN_IPADDRESS ) { + if (ntype == IS_DNS) continue; + +#ifdef LDAP_PF_INET6 + if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) { + continue; + } else +#endif + if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) { + continue; + } + if (!memcmp(altname, &addr, altnamesize)) { + break; + } + } } + if ( ret >= 0 ) { + ret = LDAP_SUCCESS; + } else { + altnamesize = sizeof(altname); + ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID, + 0, 0, altname, &altnamesize ); + if ( ret < 0 ) { + Debug( LDAP_DEBUG_ANY, + "TLS: unable to get common name from peer certificate.\n", + 0, 0, 0 ); + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } + ld->ld_error = LDAP_STRDUP( + _("TLS: unable to get CN from peer certificate")); - p = LDAP_STRDUP(buf); - X509_free(x); - return p; + } else { + ret = LDAP_LOCAL_ERROR; + if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) { + ret = LDAP_SUCCESS; + + } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) { + /* Is this a wildcard match? */ + if( domain && + (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) { + ret = LDAP_SUCCESS; + } + } + } + + if( ret == LDAP_LOCAL_ERROR ) { + altname[altnamesize] = '\0'; + Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " + "common name in certificate (%s).\n", + name, altname, 0 ); + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } + ld->ld_error = LDAP_STRDUP( + _("TLS: hostname does not match CN in peer certificate")); + } + } + gnutls_x509_crt_deinit( cert ); + return ret; } -/* what kind of hostname were we given? */ -#define IS_DNS 0 -#define IS_IP4 1 -#define IS_IP6 2 +#else /* !HAVE_GNUTLS */ int ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) @@ -1155,27 +2094,7 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) X509_free(x); return ret; } - -const char * -ldap_pvt_tls_get_peer_issuer( void *s ) -{ -#if 0 /* currently unused; see ldap_pvt_tls_get_peer_dn() if needed */ - X509 *x; - X509_NAME *xn; - char buf[2048], *p; - - x = SSL_get_peer_certificate((SSL *)s); - - if (!x) return NULL; - - xn = X509_get_issuer_name(x); - p = LDAP_STRDUP(X509_NAME_oneline(xn, buf, sizeof(buf))); - X509_free(x); - return p; -#else - return NULL; #endif -} int ldap_int_tls_config( LDAP *ld, int option, const char *arg ) @@ -1190,6 +2109,9 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg ) case LDAP_OPT_X_TLS_RANDOM_FILE: case LDAP_OPT_X_TLS_CIPHER_SUITE: case LDAP_OPT_X_TLS_DHFILE: +#ifdef HAVE_GNUTLS + case LDAP_OPT_X_TLS_CRLFILE: +#endif return ldap_pvt_tls_set_option( ld, option, (void *) arg ); case LDAP_OPT_X_TLS_REQUIRE_CERT: @@ -1267,8 +2189,7 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) case LDAP_OPT_X_TLS_CTX: *(void **)arg = lo->ldo_tls_ctx; if ( lo->ldo_tls_ctx ) { - SSL_CTX *ctx = lo->ldo_tls_ctx; - CRYPTO_add( &ctx->references, 1, CRYPTO_LOCK_SSL_CTX ); + tls_ctx_ref( lo->ldo_tls_ctx ); } break; case LDAP_OPT_X_TLS_CACERTFILE: @@ -1291,6 +2212,12 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) *(char **)arg = lo->ldo_tls_dhfile ? LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL; break; +#ifdef HAVE_GNUTLS + case LDAP_OPT_X_TLS_CRLFILE: + *(char **)arg = lo->ldo_tls_crlfile ? + LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL; + break; +#endif case LDAP_OPT_X_TLS_REQUIRE_CERT: *(int *)arg = lo->ldo_tls_require_cert; break; @@ -1304,8 +2231,12 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL; break; case LDAP_OPT_X_TLS_RANDOM_FILE: +#ifdef HAVE_OPENSSL *(char **)arg = tls_opt_randfile ? LDAP_STRDUP( tls_opt_randfile ) : NULL; +#else + *(char **)arg = NULL; +#endif break; case LDAP_OPT_X_TLS_SSL_CTX: { void *retval = 0; @@ -1373,9 +2304,9 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) case LDAP_OPT_X_TLS_CTX: if ( lo->ldo_tls_ctx ) - SSL_CTX_free( lo->ldo_tls_ctx ); + ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = arg; - CRYPTO_add( &((SSL_CTX *)arg)->references, 1, CRYPTO_LOCK_SSL_CTX ); + tls_ctx_ref( lo->ldo_tls_ctx ); return 0; case LDAP_OPT_X_TLS_CONNECT_CB: lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg; @@ -1403,6 +2334,12 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile ); lo->ldo_tls_dhfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; +#ifdef HAVE_GNUTLS + case LDAP_OPT_X_TLS_CRLFILE: + if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile ); + lo->ldo_tls_crlfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; +#endif case LDAP_OPT_X_TLS_REQUIRE_CERT: if ( !arg ) return -1; switch( *(int *) arg ) { @@ -1435,14 +2372,16 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) case LDAP_OPT_X_TLS_RANDOM_FILE: if ( ld != NULL ) return -1; +#ifdef HAVE_OPENSSL if (tls_opt_randfile ) LDAP_FREE (tls_opt_randfile ); tls_opt_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; +#endif break; case LDAP_OPT_X_TLS_NEWCTX: if ( !arg ) return -1; if ( lo->ldo_tls_ctx ) - SSL_CTX_free( lo->ldo_tls_ctx ); + ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; return ldap_int_tls_init_ctx( lo, *(int *)arg ); default: @@ -1495,6 +2434,7 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) return LDAP_SUCCESS; } +#ifdef HAVE_OPENSSL /* Derived from openssl/apps/s_cb.c */ static void tls_info_cb( const SSL *ssl, int where, int ret ) @@ -1822,6 +2762,8 @@ tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) } #endif +#endif /* HAVE_OPENSSL */ + void * ldap_pvt_tls_sb_ctx( Sockbuf *sb ) { @@ -1840,11 +2782,17 @@ ldap_pvt_tls_sb_ctx( Sockbuf *sb ) int ldap_pvt_tls_get_strength( void *s ) { -#ifdef HAVE_TLS +#ifdef HAVE_OPENSSL SSL_CIPHER *c; c = SSL_get_current_cipher((SSL *)s); return SSL_CIPHER_get_bits(c, NULL); +#elif defined(HAVE_GNUTLS) + tls_session *session = s; + gnutls_cipher_algorithm_t c; + + c = gnutls_cipher_get( session->session ); + return gnutls_cipher_get_key_size( c ); #else return 0; #endif @@ -1855,18 +2803,36 @@ int ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags ) { #ifdef HAVE_TLS + struct berval der_dn; + int rc; +#ifdef HAVE_OPENSSL X509 *x; X509_NAME *xn; - int rc; x = SSL_get_certificate((SSL *)s); if (!x) return LDAP_INVALID_CREDENTIALS; xn = X509_get_subject_name(x); - rc = ldap_X509dn2bv(xn, dn, (LDAPDN_rewrite_func *)func, flags ); + der_dn.bv_len = i2d_X509_NAME( xn, NULL ); + der_dn.bv_val = xn->bytes->data; +#elif defined(HAVE_GNUTLS) + tls_session *session = s; + const gnutls_datum_t *x; + struct berval bv; + + x = gnutls_certificate_get_ours( session->session ); + + if (!x) return LDAP_INVALID_CREDENTIALS; + + bv.bv_val = x->data; + bv.bv_len = x->size; + + x509_cert_get_dn( &bv, &der_dn, 1 ); +#endif + rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags ); return rc; -#else +#else /* !HAVE_TLS */ return LDAP_NOT_SUPPORTED; #endif } @@ -1932,3 +2898,234 @@ ldap_start_tls_s ( LDAP *ld, #endif } +/* These tags probably all belong in lber.h, but they're + * not normally encountered when processing LDAP, so maybe + * they belong somewhere else instead. + */ + +#define LBER_TAG_OID ((ber_tag_t) 0x06UL) + +/* Tags for string types used in a DirectoryString. + * + * Note that IA5string is not one of the defined choices for + * DirectoryString in X.520, but it gets used for email AVAs. + */ +#define LBER_TAG_UTF8 ((ber_tag_t) 0x0cUL) +#define LBER_TAG_PRINTABLE ((ber_tag_t) 0x13UL) +#define LBER_TAG_TELETEX ((ber_tag_t) 0x14UL) +#define LBER_TAG_IA5 ((ber_tag_t) 0x16UL) +#define LBER_TAG_UNIVERSAL ((ber_tag_t) 0x1cUL) +#define LBER_TAG_BMP ((ber_tag_t) 0x1eUL) + +static oid_name * +find_oid( struct berval *oid ) +{ + int i; + + for ( i=0; !BER_BVISNULL( &oids[i].oid ); i++ ) { + if ( oids[i].oid.bv_len != oid->bv_len ) continue; + if ( !strcmp( oids[i].oid.bv_val, oid->bv_val )) + return &oids[i]; + } + return NULL; +} + +/* Convert a structured DN from an X.509 certificate into an LDAPV3 DN. + * x509_name must be raw DER. If func is non-NULL, the + * constructed DN will use numeric OIDs to identify attributeTypes, + * and the func() will be invoked to rewrite the DN with the given + * flags. + * + * Otherwise the DN will use shortNames from a hardcoded table. + */ +int +ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func, + unsigned flags ) +{ + LDAPDN newDN; + LDAPRDN newRDN; + LDAPAVA *newAVA, *baseAVA; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + char oids[8192], *oidptr = oids, *oidbuf = NULL; + void *ptrs[2048]; + char *dn_end, *rdn_end; + int i, navas, nrdns, rc = LDAP_SUCCESS; + size_t dnsize, oidrem = sizeof(oids), oidsize = 0; + int csize; + ber_tag_t tag; + ber_len_t len; + oid_name *oidname; + + struct berval Oid, Val, oid2, *in = x509_name; + + assert( bv != NULL ); + + bv->bv_len = 0; + bv->bv_val = NULL; + + navas = 0; + nrdns = 0; + + /* A DN is a SEQUENCE of RDNs. An RDN is a SET of AVAs. + * An AVA is a SEQUENCE of attr and value. + * Count the number of AVAs and RDNs + */ + ber_init2( ber, in, LBER_USE_DER ); + tag = ber_peek_tag( ber, &len ); + if ( tag != LBER_SEQUENCE ) + return LDAP_DECODING_ERROR; + + for ( tag = ber_first_element( ber, &len, &dn_end ); + tag == LBER_SET; + tag = ber_next_element( ber, &len, dn_end )) { + nrdns++; + for ( tag = ber_first_element( ber, &len, &rdn_end ); + tag == LBER_SEQUENCE; + tag = ber_next_element( ber, &len, rdn_end )) { + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + navas++; + } + } + + /* Allocate the DN/RDN/AVA stuff as a single block */ + dnsize = sizeof(LDAPRDN) * (nrdns+1); + dnsize += sizeof(LDAPAVA *) * (navas+nrdns); + dnsize += sizeof(LDAPAVA) * navas; + if (dnsize > sizeof(ptrs)) { + newDN = (LDAPDN)LDAP_MALLOC( dnsize ); + if ( newDN == NULL ) + return LDAP_NO_MEMORY; + } else { + newDN = (LDAPDN)(char *)ptrs; + } + + newDN[nrdns] = NULL; + newRDN = (LDAPRDN)(newDN + nrdns+1); + newAVA = (LDAPAVA *)(newRDN + navas + nrdns); + baseAVA = newAVA; + + /* Rewind and start extracting */ + ber_rewind( ber ); + + tag = ber_first_element( ber, &len, &dn_end ); + for ( i = nrdns - 1; i >= 0; i-- ) { + newDN[i] = newRDN; + + for ( tag = ber_first_element( ber, &len, &rdn_end ); + tag == LBER_SEQUENCE; + tag = ber_next_element( ber, &len, rdn_end )) { + + *newRDN++ = newAVA; + tag = ber_skip_tag( ber, &len ); + tag = ber_get_stringbv( ber, &Oid, LBER_BV_NOTERM ); + if ( tag != LBER_TAG_OID ) { + rc = LDAP_DECODING_ERROR; + goto nomem; + } + + oid2.bv_val = oidptr; + oid2.bv_len = oidrem; + if ( ber_decode_oid( &Oid, &oid2 ) < 0 ) { + rc = LDAP_DECODING_ERROR; + goto nomem; + } + oidname = find_oid( &oid2 ); + if ( !oidname ) { + newAVA->la_attr = oid2; + oidptr += oid2.bv_len + 1; + oidrem -= oid2.bv_len + 1; + + /* Running out of OID buffer space? */ + if (oidrem < 128) { + if ( oidsize == 0 ) { + oidsize = sizeof(oids) * 2; + oidrem = oidsize; + oidbuf = LDAP_MALLOC( oidsize ); + if ( oidbuf == NULL ) goto nomem; + oidptr = oidbuf; + } else { + char *old = oidbuf; + oidbuf = LDAP_REALLOC( oidbuf, oidsize*2 ); + if ( oidbuf == NULL ) goto nomem; + /* Buffer moved! Fix AVA pointers */ + if ( old != oidbuf ) { + LDAPAVA *a; + long dif = oidbuf - old; + + for (a=baseAVA; a<=newAVA; a++){ + if (a->la_attr.bv_val >= old && + a->la_attr.bv_val <= (old + oidsize)) + a->la_attr.bv_val += dif; + } + } + oidptr = oidbuf + oidsize - oidrem; + oidrem += oidsize; + oidsize *= 2; + } + } + } else { + if ( func ) { + newAVA->la_attr = oidname->oid; + } else { + newAVA->la_attr = oidname->name; + } + } + tag = ber_get_stringbv( ber, &Val, LBER_BV_NOTERM ); + switch(tag) { + case LBER_TAG_UNIVERSAL: + /* This uses 32-bit ISO 10646-1 */ + csize = 4; goto to_utf8; + case LBER_TAG_BMP: + /* This uses 16-bit ISO 10646-1 */ + csize = 2; goto to_utf8; + case LBER_TAG_TELETEX: + /* This uses 8-bit, assume ISO 8859-1 */ + csize = 1; +to_utf8: rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value ); + newAVA->la_flags |= LDAP_AVA_FREE_VALUE; + if (rc != LDAP_SUCCESS) goto nomem; + newAVA->la_flags = LDAP_AVA_NONPRINTABLE; + break; + case LBER_TAG_UTF8: + newAVA->la_flags = LDAP_AVA_NONPRINTABLE; + /* This is already in UTF-8 encoding */ + case LBER_TAG_IA5: + case LBER_TAG_PRINTABLE: + /* These are always 7-bit strings */ + newAVA->la_value = Val; + default: + ; + } + newAVA->la_private = NULL; + newAVA->la_flags = LDAP_AVA_STRING; + newAVA++; + } + *newRDN++ = NULL; + tag = ber_next_element( ber, &len, dn_end ); + } + + if ( func ) { + rc = func( newDN, flags, NULL ); + if ( rc != LDAP_SUCCESS ) + goto nomem; + } + + rc = ldap_dn2bv_x( newDN, bv, LDAP_DN_FORMAT_LDAPV3, NULL ); + +nomem: + for (;baseAVA < newAVA; baseAVA++) { + if (baseAVA->la_flags & LDAP_AVA_FREE_ATTR) + LDAP_FREE( baseAVA->la_attr.bv_val ); + if (baseAVA->la_flags & LDAP_AVA_FREE_VALUE) + LDAP_FREE( baseAVA->la_value.bv_val ); + } + + if ( oidsize != 0 ) + LDAP_FREE( oidbuf ); + if ( newDN != (LDAPDN)(char *) ptrs ) + LDAP_FREE( newDN ); + return rc; +} + diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index 1eadf029f1..6a6e076b56 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -20,7 +20,7 @@ /* * LDAP URLs look like this: - * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] + * ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * where: * attributes is a comma separated list @@ -533,12 +533,17 @@ desc2str_len( LDAPURLDesc *u ) { int sep = 0; int len = 0; + int is_ipc = 0; struct berval scope; - if ( u == NULL ) { + if ( u == NULL || u->lud_scheme == NULL ) { return -1; } + if ( !strcmp( "ldapi", u->lud_scheme )) { + is_ipc = 1; + } + if ( u->lud_exts ) { len += hex_escape_len_list( u->lud_exts, URLESC_COMMA ); if ( !sep ) { @@ -547,7 +552,7 @@ desc2str_len( LDAPURLDesc *u ) } if ( u->lud_filter ) { - len += hex_escape_len( u->lud_filter, URLESC_NONE ); + len += hex_escape_len( u->lud_filter, URLESC_NONE ); if ( !sep ) { sep = 4; } @@ -561,7 +566,7 @@ desc2str_len( LDAPURLDesc *u ) } if ( u->lud_attrs ) { - len += hex_escape_len_list( u->lud_attrs, URLESC_NONE ); + len += hex_escape_len_list( u->lud_attrs, URLESC_NONE ); if ( !sep ) { sep = 2; } @@ -587,6 +592,9 @@ desc2str_len( LDAPURLDesc *u ) } else { if ( u->lud_host && u->lud_host[0] ) { len += hex_escape_len( u->lud_host, URLESC_SLASH ); + if ( !is_ipc && strchr( u->lud_host, ':' )) { + len += 2; /* IPv6, [] */ + } } } @@ -595,12 +603,14 @@ desc2str_len( LDAPURLDesc *u ) return len; } -int +static int desc2str( LDAPURLDesc *u, char *s, int len ) { int i; int sep = 0; int sofar = 0; + int is_v6 = 0; + int is_ipc = 0; struct berval scope = BER_BVNULL; if ( u == NULL ) { @@ -611,6 +621,10 @@ desc2str( LDAPURLDesc *u, char *s, int len ) return -1; } + if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) { + is_ipc = 1; + } + ldap_pvt_scope2bv( u->lud_scope, &scope ); if ( u->lud_exts ) { @@ -625,17 +639,31 @@ desc2str( LDAPURLDesc *u, char *s, int len ) sep = 1; } + if ( !is_ipc && u->lud_host && strchr( u->lud_host, ':' )) { + is_v6 = 1; + } + if ( u->lud_port ) { - len -= sprintf( s, "%s://%s:%d%n", u->lud_scheme, + len -= sprintf( s, "%s://%s%s%s:%d%n", u->lud_scheme, + is_v6 ? "[" : "", u->lud_host ? u->lud_host : "", + is_v6 ? "]" : "", u->lud_port, &sofar ); } else { len -= sprintf( s, "%s://%n", u->lud_scheme, &sofar ); if ( u->lud_host && u->lud_host[0] ) { + if ( is_v6 ) { + s[sofar++] = '['; + len--; + } i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH ); sofar += i; len -= i; + if ( is_v6 ) { + s[sofar++] = ']'; + len--; + } } } @@ -765,7 +793,7 @@ ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags LDAPURLDesc *ludp; char *p, *q, *r; - int i, enclosed; + int i, enclosed, proto, is_v6 = 0; const char *scheme = NULL; const char *url_tmp; char *url; @@ -795,6 +823,11 @@ ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags assert( scheme != NULL ); + proto = ldap_pvt_url_scheme2proto( scheme ); + if ( proto == -1 ) { + return LDAP_URL_ERR_BADSCHEME; + } + /* make working copy of the remainder of the URL */ url = LDAP_STRDUP( url_tmp ); if ( url == NULL ) { @@ -839,62 +872,83 @@ ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags /* scan forward for '/' that marks end of hostport and begin. of dn */ p = strchr( url, '/' ); + q = NULL; if( p != NULL ) { /* terminate hostport; point to start of dn */ *p++ = '\0'; + } else { + /* check for Novell kludge, see below */ + p = strchr( url, '?' ); + if ( p ) { + *p++ = '\0'; + q = p; + p = NULL; + } } - /* IPv6 syntax with [ip address]:port */ - if ( *url == '[' ) { - r = strchr( url, ']' ); - if ( r == NULL ) { - LDAP_FREE( url ); - ldap_free_urldesc( ludp ); - return LDAP_URL_ERR_BADURL; + if ( proto != LDAP_PROTO_IPC ) { + /* IPv6 syntax with [ip address]:port */ + if ( *url == '[' ) { + r = strchr( url, ']' ); + if ( r == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + *r++ = '\0'; + q = strchr( r, ':' ); + if ( q && q != r ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + is_v6 = 1; + } else { + q = strchr( url, ':' ); } - *r++ = '\0'; - q = strchr( r, ':' ); - } else { - q = strchr( url, ':' ); - } - if ( q != NULL ) { - char *next; + if ( q != NULL ) { + char *next; - *q++ = '\0'; - ldap_pvt_hex_unescape( q ); + *q++ = '\0'; + ldap_pvt_hex_unescape( q ); - if( *q == '\0' ) { - LDAP_FREE( url ); - ldap_free_urldesc( ludp ); - return LDAP_URL_ERR_BADURL; - } + if( *q == '\0' ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } - ludp->lud_port = strtol( q, &next, 10 ); - if ( next == q || next[0] != '\0' ) { - LDAP_FREE( url ); - ldap_free_urldesc( ludp ); - return LDAP_URL_ERR_BADURL; + ludp->lud_port = strtol( q, &next, 10 ); + if ( next == q || next[0] != '\0' ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_BADURL; + } + /* check for Novell kludge */ + if ( !p ) { + if ( *next != '\0' ) { + q = &next[1]; + } else { + q = NULL; + } + } } - } - if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) { - if ( strcmp( ludp->lud_scheme, "ldap" ) == 0 ) { - ludp->lud_port = LDAP_PORT; -#ifdef LDAP_CONNECTIONLESS - } else if ( strcmp( ludp->lud_scheme, "cldap" ) == 0 ) { - ludp->lud_port = LDAP_PORT; -#endif - } else if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) { - ludp->lud_port = LDAPS_PORT; + if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) { + if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) { + ludp->lud_port = LDAPS_PORT; + } else { + ludp->lud_port = LDAP_PORT; + } } } ldap_pvt_hex_unescape( url ); /* If [ip address]:port syntax, url is [ip and we skip the [ */ - ludp->lud_host = LDAP_STRDUP( url + ( *url == '[' ) ); + ludp->lud_host = LDAP_STRDUP( url + is_v6 ); if( ludp->lud_host == NULL ) { LDAP_FREE( url ); @@ -919,28 +973,25 @@ ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags * but we need to account for it. Fortunately it can't be confused with * anything real. */ - if( (p == NULL) && (q != NULL) && ((q = strchr( q, '?')) != NULL)) { - q++; + if( (p == NULL) && (q != NULL) && (*q == '?') ) { /* ? immediately followed by question */ - if( *q == '?') { - q++; - if( *q != '\0' ) { - /* parse dn part */ - ldap_pvt_hex_unescape( q ); - ludp->lud_dn = LDAP_STRDUP( q ); + q++; + if( *q != '\0' ) { + /* parse dn part */ + ldap_pvt_hex_unescape( q ); + ludp->lud_dn = LDAP_STRDUP( q ); - } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) { - ludp->lud_dn = LDAP_STRDUP( "" ); + } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) { + ludp->lud_dn = LDAP_STRDUP( "" ); - } else { - check_dn = 0; - } + } else { + check_dn = 0; + } - if ( check_dn && ludp->lud_dn == NULL ) { - LDAP_FREE( url ); - ldap_free_urldesc( ludp ); - return LDAP_URL_ERR_MEM; - } + if ( check_dn && ludp->lud_dn == NULL ) { + LDAP_FREE( url ); + ldap_free_urldesc( ludp ); + return LDAP_URL_ERR_MEM; } } diff --git a/libraries/libldap/urltest.c b/libraries/libldap/urltest.c index 87db0b676a..59c6db78be 100644 --- a/libraries/libldap/urltest.c +++ b/libraries/libldap/urltest.c @@ -122,5 +122,7 @@ main(int argc, char *argv[]) } } + fprintf( stdout, "URL: %s\n", ldap_url_desc2str( lud )); + return EXIT_SUCCESS; } diff --git a/libraries/libldap/vlvctrl.c b/libraries/libldap/vlvctrl.c index f301a2e641..f0c4cb446e 100644 --- a/libraries/libldap/vlvctrl.c +++ b/libraries/libldap/vlvctrl.c @@ -210,7 +210,6 @@ ldap_create_vlv_control( LDAPControl **ctrlp ) { struct berval value; - BerElement *ber; if ( ctrlp == NULL ) { ld->ld_errno = LDAP_PARAM_ERROR; @@ -219,19 +218,12 @@ ldap_create_vlv_control( ld->ld_errno = ldap_create_vlv_control_value( ld, vlvinfop, &value ); if ( ld->ld_errno == LDAP_SUCCESS ) { - if ((ber = ldap_alloc_ber_with_options(ld)) == NULL) { - ld->ld_errno = LDAP_NO_MEMORY; - return LDAP_NO_MEMORY; - } - ld->ld_errno = ldap_create_control( LDAP_CONTROL_VLVREQUEST, - ber, 1, ctrlp ); - if ( ld->ld_errno == LDAP_SUCCESS ) { - (*ctrlp)->ldctl_value = value; - } else { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_VLVREQUEST, + 1, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { LDAP_FREE( value.bv_val ); } - ber_free(ber, 1); } return ld->ld_errno; diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in index f52f427518..48df9f7550 100644 --- a/libraries/libldap_r/Makefile.in +++ b/libraries/libldap_r/Makefile.in @@ -28,7 +28,7 @@ XXSRCS = apitest.c test.c \ request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \ init.c options.c print.c string.c util-int.c schema.c \ charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \ - turn.c ppolicy.c dds.c txn.c ldap_sync.c + turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c SRCS = threads.c rdwr.c rmutex.c tpool.c rq.c \ thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \ thr_pth.c thr_stub.c thr_debug.c @@ -44,7 +44,7 @@ OBJS = threads.lo rdwr.lo rmutex.lo tpool.lo rq.lo \ request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \ - turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo + turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/libraries/libldap_r/thr_debug.c b/libraries/libldap_r/thr_debug.c index 87ed67fa02..2d271252bc 100644 --- a/libraries/libldap_r/thr_debug.c +++ b/libraries/libldap_r/thr_debug.c @@ -57,7 +57,7 @@ * * Run-time configuration: * - * Setup of memory debugging tools: + * Memory debugging tools: * Tools that report uninitialized memory accesses should disable * such warnings about the function debug_already_initialized(). * Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG. @@ -274,19 +274,16 @@ get_options( void ) if( s != NULL ) { while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) { size_t optlen = strcspn( s, ", \t\r\n" ); - const struct option_info_s *oi; - for( oi = option_info; oi->name; oi++ ) { - if( strncasecmp( oi->name, s, optlen ) == 0 ) { - if( oi->name && oi->name[optlen] == '\0' ) { - *oi->var = oi->val; - } else { - fprintf( stderr, - "== thr_debug: Unknown $%s option '%.*s' ==\n", - "LDAP_THREAD_DEBUG", (int) optlen, s ); - } - break; - } - } + const struct option_info_s *oi = option_info; + while( oi->name && + (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) ) + oi++; + if( oi->name ) + *oi->var = oi->val; + else + fprintf( stderr, + "== thr_debug: Unknown $%s option '%.*s' ==\n", + "LDAP_THREAD_DEBUG", (int) optlen, s ); s += optlen; } } @@ -383,9 +380,8 @@ ldap_debug_thread_assert_mutex_owner( static void debug_noop( void ); static int debug_already_initialized( const ldap_debug_usage_info_t *usage ); -/* Names used to give clearer error messages */ +/* Name used for clearer error message */ #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage )) -enum { Is_destroyed = 1 }; #define DUMMY_ADDR(usage) \ (wraptype == Wrap_scramble \ @@ -408,18 +404,22 @@ init_usage( ldap_debug_usage_info_t *usage, const char *msg ) free( dummy ); } ); } - usage->self = SCRAMBLE( usage ); if( wraptype != Wrap_noalloc ) { unsigned char *dummy = malloc( 1 ); assert( dummy != NULL ); if( wraptype == Wrap_scramble ) { usage->mem.num = SCRAMBLE( dummy ); + /* Verify that ptr<->integer casts work on this host */ assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy ); } else { usage->mem.ptr = dummy + wrap_offset; } } + } else { + /* Unused, but set for readability in debugger */ + usage->mem.ptr = NULL; } + usage->self = SCRAMBLE( usage ); /* If nomem, only for debugger */ usage->magic = ldap_debug_magic; usage->state = ldap_debug_state_inited; } @@ -428,6 +428,8 @@ init_usage( ldap_debug_usage_info_t *usage, const char *msg ) static void check_usage( const ldap_debug_usage_info_t *usage, const char *msg ) { + enum { Is_destroyed = 1 }; /* Name used for clearer error message */ + if( usage->magic != ldap_debug_magic ) { ERROR( usage->magic, msg ); return; @@ -474,14 +476,24 @@ debug_noop( void ) { } -/* Return true if the resource is initialized and not copied/realloced. */ -/* Valid programs access uninitialized memory here unless "noreinit". */ +/* + * Valid programs access uninitialized memory here unless "noreinit". + * + * Returns true if the resource is initialized and not copied/realloced. + */ static int debug_already_initialized( const ldap_debug_usage_info_t *usage ) { - return (usage->state == ldap_debug_state_inited && - !IS_COPY_OR_MOVED( usage ) && - usage->magic == ldap_debug_magic); + /* + * 'ret' keeps the Valgrind warning "Conditional jump or move + * depends on uninitialised value(s)" _inside_ this function. + */ + volatile int ret = 0; + if( usage->state == ldap_debug_state_inited ) + if( !IS_COPY_OR_MOVED( usage ) ) + if( usage->magic == ldap_debug_magic ) + ret = 1; + return ret; } #endif /* LDAP_THREAD_DEBUG_WRAP */ @@ -489,7 +501,7 @@ debug_already_initialized( const ldap_debug_usage_info_t *usage ) #if !(LDAP_THREAD_DEBUG_THREAD_ID +0) -typedef int ldap_debug_thread_t; +typedef void ldap_debug_thread_t; #define init_thread_info() {} #define with_thread_info_lock(statements) { statements; } #define thread_info_detached(t) 0 @@ -577,13 +589,13 @@ remove_thread_info( ldap_debug_thread_t *t, const char *msg ) (thread_info[thread_info_used] = t )->idx = thread_info_used; } -ldap_debug_thread_t * -get_thread_info( ldap_pvt_thread_t *thread, const char *msg ) +static ldap_debug_thread_t * +get_thread_info( ldap_pvt_thread_t thread, const char *msg ) { unsigned int i; ldap_debug_thread_t *t; for( i = 0; i < thread_info_used; i++ ) { - if( ldap_pvt_thread_equal( *thread, thread_info[i]->wrapped ) ) + if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) ) break; } ERROR_IF( i == thread_info_used, msg ); @@ -714,7 +726,9 @@ static void thread_exiting( const char *how, const char *msg ) { ldap_pvt_thread_t thread; +#if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */ ERROR_IF( !threading_enabled, msg ); +#endif thread = ldap_pvt_thread_self(); if( tracethreads ) { char buf[40]; @@ -723,8 +737,7 @@ thread_exiting( const char *how, const char *msg ) } if( threadID ) { with_thread_info_lock({ - ldap_debug_thread_t *t = get_thread_info( - &thread, msg ); + ldap_debug_thread_t *t = get_thread_info( thread, msg ); if( thread_info_detached( t ) ) remove_thread_info( t, msg ); }); @@ -786,6 +799,8 @@ ldap_pvt_thread_create( } if( rc ) { ERROR( rc, "ldap_pvt_thread_create" ); + if( wrap_threads ) + free( arg ); } else { if( tracethreads ) { char buf[40], buf2[40]; @@ -816,7 +831,7 @@ ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) } if( threadID ) with_thread_info_lock( { - t = get_thread_info( &thread, "ldap_pvt_thread_join" ); + t = get_thread_info( thread, "ldap_pvt_thread_join" ); ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" ); } ); rc = ldap_int_thread_join( thread, thread_return ); @@ -1159,7 +1174,7 @@ ldap_pvt_thread_pool_submit( { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" ); - has_pool = (tpool != NULL && *tpool != NULL); + has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_submit( tpool, start_routine, arg ); if( has_pool ) ERROR_IF( rc, "ldap_pvt_thread_pool_submit" ); @@ -1187,7 +1202,7 @@ ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending ) { int rc, has_pool; ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" ); - has_pool = (tpool != NULL && *tpool != NULL); + has_pool = (tpool && *tpool); rc = ldap_int_thread_pool_destroy( tpool, run_pending ); if( has_pool ) { if( rc ) { diff --git a/libraries/libldap_r/thr_posix.c b/libraries/libldap_r/thr_posix.c index f378cfcaf8..4e0a45b432 100644 --- a/libraries/libldap_r/thr_posix.c +++ b/libraries/libldap_r/thr_posix.c @@ -55,6 +55,12 @@ static pthread_mutexattr_t mutex_attr; # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT &mutex_attr #endif +#if HAVE_PTHREADS < 7 +#define ERRVAL(val) ((val) < 0 ? errno : 0) +#else +#define ERRVAL(val) (val) +#endif + int ldap_int_thread_initialize( void ) { @@ -84,7 +90,7 @@ ldap_pvt_thread_set_concurrency(int n) { #ifdef HAVE_PTHREAD_SETCONCURRENCY return pthread_setconcurrency( n ); -#elif HAVE_THR_SETCONCURRENCY +#elif defined(HAVE_THR_SETCONCURRENCY) return thr_setconcurrency( n ); #else return 0; @@ -98,7 +104,7 @@ ldap_pvt_thread_get_concurrency(void) { #ifdef HAVE_PTHREAD_GETCONCURRENCY return pthread_getconcurrency(); -#elif HAVE_THR_GETCONCURRENCY +#elif defined(HAVE_THR_GETCONCURRENCY) return thr_getconcurrency(); #else return 0; @@ -157,6 +163,7 @@ ldap_pvt_thread_create( ldap_pvt_thread_t * thread, #else rtn = pthread_create( thread, &attr, start_routine, arg ); #endif + #if HAVE_PTHREADS > 5 pthread_attr_destroy(&attr); #else @@ -183,26 +190,18 @@ ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return ) { #if HAVE_PTHREADS < 7 void *dummy; - if (thread_return==NULL) thread_return=&dummy; - - if ( pthread_join( thread, thread_return ) < 0 ) return errno; - return 0; -#else - return pthread_join( thread, thread_return ); #endif + return ERRVAL( pthread_join( thread, thread_return ) ); } int ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo ) { -#if ( HAVE_PTHREAD_KILL && HAVE_PTHREADS > 6 ) +#if defined(HAVE_PTHREAD_KILL) && HAVE_PTHREADS > 4 /* MacOS 10.1 is detected as v10 but has no pthread_kill() */ - return pthread_kill( thread, signo ); -#elif ( HAVE_PTHREAD_KILL && HAVE_PTHREADS > 4 ) - if ( pthread_kill( thread, signo ) < 0 ) return errno; - return 0; + return ERRVAL( pthread_kill( thread, signo ) ); #else /* pthread package with DCE */ if (kill( getpid(), signo )<0) @@ -223,7 +222,8 @@ ldap_pvt_thread_yield( void ) select( 0, NULL, NULL, NULL, &tv ); #endif return 0; -#elif HAVE_THR_YIELD + +#elif defined(HAVE_THR_YIELD) thr_yield(); return 0; @@ -237,6 +237,7 @@ ldap_pvt_thread_yield( void ) #elif HAVE_PTHREADS == 6 pthread_yield(NULL); return 0; + #else pthread_yield(); return 0; @@ -246,114 +247,64 @@ ldap_pvt_thread_yield( void ) int ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond ) { -#if HAVE_PTHREADS < 7 - if ( pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ) < 0 ) - return errno; - return 0; -#else - return pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ); -#endif + return ERRVAL( pthread_cond_init( + cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ) ); } int ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond ) { -#if HAVE_PTHREADS < 7 - if ( pthread_cond_destroy( cond ) < 0 ) return errno; - return 0; -#else - return pthread_cond_destroy( cond ); -#endif + return ERRVAL( pthread_cond_destroy( cond ) ); } int ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond ) { -#if HAVE_PTHREADS < 7 - if ( pthread_cond_signal( cond ) < 0 ) return errno; - return 0; -#else - return pthread_cond_signal( cond ); -#endif + return ERRVAL( pthread_cond_signal( cond ) ); } int ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond ) { -#if HAVE_PTHREADS < 7 - if ( pthread_cond_broadcast( cond ) < 0 ) return errno; - return 0; -#else - return pthread_cond_broadcast( cond ); -#endif + return ERRVAL( pthread_cond_broadcast( cond ) ); } int ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_cond_wait( cond, mutex ) < 0 ) return errno; - return 0; -#else - return pthread_cond_wait( cond, mutex ); -#endif + return ERRVAL( pthread_cond_wait( cond, mutex ) ); } int ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT )<0) - return errno; - return 0; -#else - return pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT ); -#endif + return ERRVAL( pthread_mutex_init( + mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT ) ); } int ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_mutex_destroy( mutex ) < 0 ) return errno; - return 0; -#else - return pthread_mutex_destroy( mutex ); -#endif + return ERRVAL( pthread_mutex_destroy( mutex ) ); } int ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_mutex_lock( mutex ) < 0 ) return errno; - return 0; -#else - return pthread_mutex_lock( mutex ); -#endif + return ERRVAL( pthread_mutex_lock( mutex ) ); } int ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_mutex_trylock( mutex ) < 0 ) return errno; - return 0; -#else - return pthread_mutex_trylock( mutex ); -#endif + return ERRVAL( pthread_mutex_trylock( mutex ) ); } int ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex ) { -#if HAVE_PTHREADS < 7 - if ( pthread_mutex_unlock( mutex ) < 0 ) return errno; - return 0; -#else - return pthread_mutex_unlock( mutex ); -#endif + return ERRVAL( pthread_mutex_unlock( mutex ) ); } ldap_pvt_thread_t ldap_pvt_thread_self( void ) @@ -366,83 +317,43 @@ ldap_pvt_thread_t ldap_pvt_thread_self( void ) int ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_init( rw, NULL ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_init( rw, NULL ); -#endif + return ERRVAL( pthread_rwlock_init( rw, NULL ) ); } int ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_destroy( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_destroy( rw ); -#endif + return ERRVAL( pthread_rwlock_destroy( rw ) ); } int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_rdlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_rdlock( rw ); -#endif + return ERRVAL( pthread_rwlock_rdlock( rw ) ); } int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_tryrdlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_tryrdlock( rw ); -#endif + return ERRVAL( pthread_rwlock_tryrdlock( rw ) ); } int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_unlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_unlock( rw ); -#endif + return ERRVAL( pthread_rwlock_unlock( rw ) ); } int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_wrlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_wrlock( rw ); -#endif + return ERRVAL( pthread_rwlock_wrlock( rw ) ); } int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_trywrlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_trywrlock( rw ); -#endif + return ERRVAL( pthread_rwlock_trywrlock( rw ) ); } int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw ) { -#if HAVE_PTHREADS < 7 - if ( pthread_rwlock_unlock( rw ) < 0 ) return errno; - return 0; -#else - return pthread_rwlock_unlock( rw ); -#endif + return ERRVAL( pthread_rwlock_unlock( rw ) ); } #endif /* HAVE_PTHREAD_RWLOCK_DESTROY */ diff --git a/libraries/libldap_r/tpool.c b/libraries/libldap_r/tpool.c index 1b18ff8fe0..fa1d2ae462 100644 --- a/libraries/libldap_r/tpool.c +++ b/libraries/libldap_r/tpool.c @@ -34,10 +34,10 @@ typedef enum ldap_int_thread_pool_state_e { LDAP_INT_THREAD_POOL_RUNNING, LDAP_INT_THREAD_POOL_FINISHING, - LDAP_INT_THREAD_POOL_STOPPING, - LDAP_INT_THREAD_POOL_PAUSING + LDAP_INT_THREAD_POOL_STOPPING } ldap_int_thread_pool_state_t; +/* Thread-specific key with data and optional free function */ typedef struct ldap_int_thread_key_s { void *ltk_key; void *ltk_data; @@ -48,48 +48,76 @@ typedef struct ldap_int_thread_key_s { * We don't expect to use many... */ #define MAXKEYS 32 + +/* Max number of threads */ #define LDAP_MAXTHR 1024 /* must be a power of 2 */ +/* Context: thread ID and thread-specific key/data pairs */ typedef struct ldap_int_thread_userctx_s { ldap_pvt_thread_t ltu_id; ldap_int_thread_key_t ltu_key[MAXKEYS]; } ldap_int_thread_userctx_t; -static ldap_pvt_thread_t tid_zero; +/* Simple {thread ID -> context} hash table; key=ctx->ltu_id. + * Protected by ldap_pvt_thread_pool_mutex except during pauses, + * when it is read-only (used by pool_purgekey and pool_context). + * Protected by tpool->ltp_mutex during pauses. + */ static struct { - ldap_pvt_thread_t id; ldap_int_thread_userctx_t *ctx; + /* ctx is valid when not NULL or DELETED_THREAD_CTX */ +# define DELETED_THREAD_CTX (&ldap_int_main_thrctx + 1) /* dummy addr */ } thread_keys[LDAP_MAXTHR]; - -typedef struct ldap_int_thread_ctx_s { +#define TID_HASH(tid, hash) do { \ + unsigned const char *ptr_ = (unsigned const char *)&(tid); \ + unsigned i_; \ + for (i_ = 0, (hash) = ptr_[0]; ++i_ < sizeof(tid);) \ + (hash) += ((hash) << 5) ^ ptr_[i_]; \ +} while(0) + + +/* Task for a thread to perform */ +typedef struct ldap_int_thread_task_s { union { - LDAP_STAILQ_ENTRY(ldap_int_thread_ctx_s) q; - LDAP_SLIST_ENTRY(ldap_int_thread_ctx_s) l; - LDAP_SLIST_ENTRY(ldap_int_thread_ctx_s) al; - } ltc_next; - ldap_pvt_thread_start_t *ltc_start_routine; - void *ltc_arg; -} ldap_int_thread_ctx_t; + LDAP_STAILQ_ENTRY(ldap_int_thread_task_s) q; + LDAP_SLIST_ENTRY(ldap_int_thread_task_s) l; + } ltt_next; + ldap_pvt_thread_start_t *ltt_start_routine; + void *ltt_arg; +} ldap_int_thread_task_t; struct ldap_int_thread_pool_s { LDAP_STAILQ_ENTRY(ldap_int_thread_pool_s) ltp_next; + + /* protect members below, and protect thread_keys[] during pauses */ ldap_pvt_thread_mutex_t ltp_mutex; + + /* not paused and something to do for pool_() */ ldap_pvt_thread_cond_t ltp_cond; + + /* ltp_active_count <= 1 && ltp_pause */ ldap_pvt_thread_cond_t ltp_pcond; - LDAP_STAILQ_HEAD(tcq, ldap_int_thread_ctx_s) ltp_pending_list; - LDAP_SLIST_HEAD(tcl, ldap_int_thread_ctx_s) ltp_free_list; - LDAP_SLIST_HEAD(tclq, ldap_int_thread_ctx_s) ltp_active_list; + + /* pending tasks, and unused task objects */ + LDAP_STAILQ_HEAD(tcq, ldap_int_thread_task_s) ltp_pending_list; + LDAP_SLIST_HEAD(tcl, ldap_int_thread_task_s) ltp_free_list; + ldap_int_thread_pool_state_t ltp_state; - long ltp_max_count; - long ltp_max_pending; - long ltp_pending_count; - long ltp_active_count; - long ltp_open_count; - long ltp_starting; + + /* some active request needs to be the sole active request */ + int ltp_pause; + + long ltp_max_count; /* max number of threads in pool, or 0 */ + long ltp_max_pending; /* max pending or paused requests, or 0 */ + long ltp_pending_count; /* pending or paused requests */ + long ltp_active_count; /* active, not paused requests */ + long ltp_open_count; /* number of threads */ + long ltp_starting; /* currenlty starting threads */ }; +static int ldap_int_has_thread_pool = 0; static LDAP_STAILQ_HEAD(tpq, ldap_int_thread_pool_s) ldap_int_thread_pool_list = LDAP_STAILQ_HEAD_INITIALIZER(ldap_int_thread_pool_list); @@ -98,16 +126,13 @@ static ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex; static void *ldap_int_thread_pool_wrapper( void *pool ); -static ldap_pvt_thread_t ldap_int_main_tid; - +/* Context of the main thread */ static ldap_int_thread_userctx_t ldap_int_main_thrctx; int ldap_int_thread_pool_startup ( void ) { - ldap_int_main_tid = ldap_pvt_thread_self(); - ldap_int_main_thrctx.ltu_id = ldap_int_main_tid; - + ldap_int_main_thrctx.ltu_id = ldap_pvt_thread_self(); return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex); } @@ -123,131 +148,8 @@ ldap_int_thread_pool_shutdown ( void ) return(0); } -typedef struct ldap_lazy_sem_t { - ldap_pvt_thread_mutex_t ls_mutex; - ldap_pvt_thread_cond_t ls_cond; - int ls_sem_value; - /* - * when more than ls_lazy_count number of resources - * becmoes available, the thread wating for the resources will - * be waken up in order to prevent frequent blocking/waking-up - */ - unsigned int ls_lazy_count; - /* - * only one thread(listener) will wait on this semaphore - * using a flag instead of a list - */ - int ls_wait; -} ldap_lazy_sem_t; - -ldap_lazy_sem_t* thread_pool_sem = NULL; - -int -ldap_lazy_sem_init( unsigned int value, unsigned int lazyness ) -{ - thread_pool_sem = (ldap_lazy_sem_t*) LDAP_CALLOC(1, - sizeof( ldap_lazy_sem_t )); - - if( thread_pool_sem == NULL ) return -1; - - ldap_pvt_thread_mutex_init( &thread_pool_sem->ls_mutex ); - ldap_pvt_thread_cond_init( &thread_pool_sem->ls_cond ); - thread_pool_sem->ls_sem_value = value; - thread_pool_sem->ls_lazy_count = lazyness; - thread_pool_sem->ls_wait = 0; - - return 0; -} - -/* FIXME: move to some approprite header */ -int ldap_lazy_sem_dec( ldap_lazy_sem_t* ls ); -int ldap_lazy_sem_wait ( ldap_lazy_sem_t* ls ); - -/* - * ldap_lazy_sem_wait is used if a caller is blockable(listener). - * Otherwise use ldap_lazy_sem_dec (worker) - */ -int -ldap_lazy_sem_op_submit( ldap_lazy_sem_t* ls ) -{ - if ( ls == NULL ) return -1; - - /* only worker thread has its thread ctx */ - if ( ldap_pvt_thread_pool_context() ) { - /* worker thread */ - return ldap_lazy_sem_dec( ls ); - } else { - /* listener */ - return ldap_lazy_sem_wait( ls ); - } -} - -/* - * test if given semaphore's count is zero. - * If 0, the caller is blocked - * If not, the count is decremented. - */ -int -ldap_lazy_sem_wait ( ldap_lazy_sem_t* ls ) -{ - ldap_pvt_thread_mutex_lock( &ls->ls_mutex ); - -lazy_sem_retry: - if ( ls->ls_sem_value <= 0 ) { - /* no more avaliable resources */ - ls->ls_wait = 1; - ldap_pvt_thread_cond_wait( &ls->ls_cond, &ls->ls_mutex ); - goto lazy_sem_retry; - } else { - /* avaliable resources */ - ls->ls_sem_value--; - } - - ldap_pvt_thread_mutex_unlock( &ls->ls_mutex ); - - return 0; -} - -/* - * decrement the count without blocking - * even when the count becomes less than or equal to 0 - */ -int -ldap_lazy_sem_dec( ldap_lazy_sem_t* ls ) -{ - ldap_pvt_thread_mutex_lock( &ls->ls_mutex ); - - ls->ls_sem_value--; - - ldap_pvt_thread_mutex_unlock( &ls->ls_mutex ); - - return 0; -} - -/* - * Increment the count by one and test if it is greater or - * equal to lazyness. If it is, wake up a blocked thread. - */ -int -ldap_lazy_sem_post( ldap_lazy_sem_t* ls ) -{ - if( ls == NULL ) return (-1); - - ldap_pvt_thread_mutex_lock( &ls->ls_mutex ); - - ls->ls_sem_value++; - if ( ls->ls_wait ) { - if ( ls->ls_sem_value >= ls->ls_lazy_count ) { - ls->ls_wait = 0; - ldap_pvt_thread_cond_signal( &ls->ls_cond ); - } - } - - ldap_pvt_thread_mutex_unlock( &ls->ls_mutex ); - - return 0; -} +/* Create a thread pool */ int ldap_pvt_thread_pool_init ( ldap_pvt_thread_pool_t *tpool, @@ -257,6 +159,14 @@ ldap_pvt_thread_pool_init ( ldap_pvt_thread_pool_t pool; int rc; + /* multiple pools are currently not supported (ITS#4943) */ + assert(!ldap_int_has_thread_pool); + + if (! (0 <= max_threads && max_threads <= LDAP_MAXTHR)) + max_threads = 0; + if (max_pending < 0) + max_pending = 0; + *tpool = NULL; pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1, sizeof(struct ldap_int_thread_pool_s)); @@ -272,12 +182,13 @@ ldap_pvt_thread_pool_init ( rc = ldap_pvt_thread_cond_init(&pool->ltp_pcond); if (rc != 0) return(rc); + + ldap_int_has_thread_pool = 1; pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING; pool->ltp_max_count = max_threads; pool->ltp_max_pending = max_pending; LDAP_STAILQ_INIT(&pool->ltp_pending_list); LDAP_SLIST_INIT(&pool->ltp_free_list); - LDAP_SLIST_INIT(&pool->ltp_active_list); ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); LDAP_STAILQ_INSERT_TAIL(&ldap_int_thread_pool_list, pool, ltp_next); ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); @@ -307,6 +218,7 @@ ldap_pvt_thread_pool_init ( ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); LDAP_STAILQ_REMOVE(ldap_int_thread_pool_list, pool, ldap_int_thread_pool_s, ltp_next); + ldap_int_has_thread_pool = 0; ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); ldap_pvt_thread_cond_destroy(&pool->ltp_pcond); ldap_pvt_thread_cond_destroy(&pool->ltp_cond); @@ -320,18 +232,15 @@ ldap_pvt_thread_pool_init ( return(0); } -#define TID_HASH(tid, hash) do { unsigned i; \ - unsigned char *ptr = (unsigned char *)&(tid); \ - for (i=0, hash=0; iltp_mutex); - if ((pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING && - pool->ltp_state != LDAP_INT_THREAD_POOL_PAUSING) - || (pool->ltp_max_pending > 0 + if (pool->ltp_state != LDAP_INT_THREAD_POOL_RUNNING + || (pool->ltp_max_pending && pool->ltp_pending_count >= pool->ltp_max_pending)) { ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(-1); } - ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list); - if (ctx) { - LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l); + + task = LDAP_SLIST_FIRST(&pool->ltp_free_list); + if (task) { + LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltt_next.l); } else { - ctx = (ldap_int_thread_ctx_t *) LDAP_MALLOC( - sizeof(ldap_int_thread_ctx_t)); - if (ctx == NULL) { + task = (ldap_int_thread_task_t *) LDAP_MALLOC(sizeof(*task)); + if (task == NULL) { ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(-1); } } - ctx->ltc_start_routine = start_routine; - ctx->ltc_arg = arg; + task->ltt_start_routine = start_routine; + task->ltt_arg = arg; pool->ltp_pending_count++; - LDAP_STAILQ_INSERT_TAIL(&pool->ltp_pending_list, ctx, ltc_next.q); - if (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) { + LDAP_STAILQ_INSERT_TAIL(&pool->ltp_pending_list, task, ltt_next.q); + if (pool->ltp_pause) { ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(0); } ldap_pvt_thread_cond_signal(&pool->ltp_cond); if (pool->ltp_open_count < pool->ltp_active_count + pool->ltp_pending_count - && (pool->ltp_open_count < pool->ltp_max_count || - pool->ltp_max_count <= 0 )) + && (pool->ltp_open_count < + (pool->ltp_max_count ? pool->ltp_max_count : LDAP_MAXTHR))) { pool->ltp_open_count++; pool->ltp_starting++; - need_thread = 1; - } - ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); - -#ifdef LDAP_PVT_THREAD_POOL_SEM_LOAD_CONTROL - ldap_lazy_sem_op_submit( thread_pool_sem ); -#endif - - if (need_thread) { - int rc; - - ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); - - rc = ldap_pvt_thread_create( &thr, 1, - ldap_int_thread_pool_wrapper, pool ); - if (rc == 0) { - int hash; - pool->ltp_starting--; - - /* assign this thread ID to a key slot; start - * at the thread ID itself (mod LDAP_MAXTHR) and - * look for an empty slot. - */ - TID_HASH(thr, hash); - for (rc = hash & (LDAP_MAXTHR-1); - !ldap_pvt_thread_equal(thread_keys[rc].id, tid_zero); - rc = (rc+1) & (LDAP_MAXTHR-1)); - thread_keys[rc].id = thr; - } else { + if (0 != ldap_pvt_thread_create( + &thr, 1, ldap_int_thread_pool_wrapper, pool)) + { /* couldn't create thread. back out of * ltp_open_count and check for even worse things. */ - pool->ltp_open_count--; pool->ltp_starting--; + pool->ltp_open_count--; if (pool->ltp_open_count == 0) { /* no open threads at all?!? */ - ldap_int_thread_ctx_t *ptr; - LDAP_STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltc_next.q) - if (ptr == ctx) break; - if (ptr == ctx) { - /* no open threads, context not handled, so - * back out of ltp_pending_count, free the context, + ldap_int_thread_task_t *ptr; + + /* let pool_destroy know there are no more threads */ + ldap_pvt_thread_cond_signal(&pool->ltp_cond); + + LDAP_STAILQ_FOREACH(ptr, &pool->ltp_pending_list, ltt_next.q) + if (ptr == task) break; + if (ptr == task) { + /* no open threads, task not handled, so + * back out of ltp_pending_count, free the task, * report the error. */ - LDAP_STAILQ_REMOVE(&pool->ltp_pending_list, ctx, - ldap_int_thread_ctx_s, ltc_next.q); - pool->ltp_pending_count++; + LDAP_STAILQ_REMOVE(&pool->ltp_pending_list, task, + ldap_int_thread_task_s, ltt_next.q); + pool->ltp_pending_count--; ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); - LDAP_FREE(ctx); + LDAP_FREE(task); return(-1); } } /* there is another open thread, so this - * context will be handled eventually. - * continue on and signal that the context - * is waiting. + * task will be handled eventually. + * continue on, we have signalled that + * the task is waiting. */ } - ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(0); } +/* Set max #threads. value <= 0 means max supported #threads (LDAP_MAXTHR) */ int -ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads ) +ldap_pvt_thread_pool_maxthreads( + ldap_pvt_thread_pool_t *tpool, + int max_threads ) { struct ldap_int_thread_pool_s *pool; + if (! (0 <= max_threads && max_threads <= LDAP_MAXTHR)) + max_threads = 0; + if (tpool == NULL) return(-1); @@ -463,8 +355,12 @@ ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads return(0); } +/* Inspect the pool */ int -ldap_pvt_thread_pool_query ( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_pool_param_t param, void *value ) +ldap_pvt_thread_pool_query( + ldap_pvt_thread_pool_t *tpool, + ldap_pvt_thread_pool_param_t param, + void *value ) { struct ldap_int_thread_pool_s *pool; int count = -1; @@ -526,21 +422,27 @@ ldap_pvt_thread_pool_query ( ldap_pvt_thread_pool_t *tpool, ldap_pvt_thread_pool { "running", LDAP_INT_THREAD_POOL_RUNNING }, { "finishing", LDAP_INT_THREAD_POOL_FINISHING }, { "stopping", LDAP_INT_THREAD_POOL_STOPPING }, - { "pausing", LDAP_INT_THREAD_POOL_PAUSING }, { NULL } }; int i; - for ( i = 0; str2state[ i ].name != NULL; i++ ) { - if ( str2state[ i ].state == pool->ltp_state ) { - break; + if ( pool->ltp_pause ) { + *((char **)value) = "pausing"; + } else { + for ( i = 0; str2state[ i ].name != NULL; i++ ) { + if ( str2state[ i ].state == pool->ltp_state ) { + break; + } } + *((char **)value) = str2state[ i ].name; } - *((char **)value) = str2state[ i ].name; - if ( str2state[ i ].name != NULL ) { + if ( *((char **)value) != NULL ) { count = -2; } } break; + + case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN: + break; } ldap_pvt_thread_mutex_unlock( &pool->ltp_mutex ); @@ -570,11 +472,12 @@ ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool ) return rc; } +/* Destroy the pool after making its threads finish */ int ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) { struct ldap_int_thread_pool_s *pool, *pptr; - ldap_int_thread_ctx_t *ctx; + ldap_int_thread_task_t *task; if (tpool == NULL) return(-1); @@ -598,73 +501,85 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) ? LDAP_INT_THREAD_POOL_FINISHING : LDAP_INT_THREAD_POOL_STOPPING; - if ( pool->ltp_open_count ) { - ldap_pvt_thread_cond_broadcast(&pool->ltp_cond); + while (pool->ltp_open_count) { + if (!pool->ltp_pause) + ldap_pvt_thread_cond_broadcast(&pool->ltp_cond); ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); } ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); - while ((ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list)) != NULL) + while ((task = LDAP_STAILQ_FIRST(&pool->ltp_pending_list)) != NULL) { - LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q); - LDAP_FREE(ctx); + LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltt_next.q); + LDAP_FREE(task); } - while ((ctx = LDAP_SLIST_FIRST(&pool->ltp_free_list)) != NULL) + while ((task = LDAP_SLIST_FIRST(&pool->ltp_free_list)) != NULL) { - LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltc_next.l); - LDAP_FREE(ctx); + LDAP_SLIST_REMOVE_HEAD(&pool->ltp_free_list, ltt_next.l); + LDAP_FREE(task); } ldap_pvt_thread_cond_destroy(&pool->ltp_pcond); ldap_pvt_thread_cond_destroy(&pool->ltp_cond); ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex); LDAP_FREE(pool); -#ifdef LDAP_PVT_THREAD_POOL_SEM_LOAD_CONTROL - if ( thread_pool_sem ) { - LDAP_FREE( thread_pool_sem ); - } -#endif + ldap_int_has_thread_pool = 0; return(0); } +/* Thread loop. Accept and handle submitted tasks. */ static void * ldap_int_thread_pool_wrapper ( void *xpool ) { struct ldap_int_thread_pool_s *pool = xpool; - ldap_int_thread_ctx_t *ctx; - ldap_int_thread_userctx_t uctx; - int i, keyslot, hash; + ldap_int_thread_task_t *task; + ldap_int_thread_userctx_t ctx, *kctx; + unsigned i, keyslot, hash; - if (pool == NULL) - return NULL; + assert(pool != NULL); for ( i=0; iltp_mutex); - /* store pointer to our keys */ - TID_HASH(uctx.ltu_id, hash); - for (i = hash & (LDAP_MAXTHR-1); - !ldap_pvt_thread_equal(thread_keys[i].id, uctx.ltu_id); - i = (i+1) & (LDAP_MAXTHR-1)); - thread_keys[i].ctx = &uctx; - keyslot = i; - - while (pool->ltp_state != LDAP_INT_THREAD_POOL_STOPPING) { - ctx = LDAP_STAILQ_FIRST(&pool->ltp_pending_list); - if (ctx) { - LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltc_next.q); - } else { + /* thread_keys[] is read-only when paused */ + while (pool->ltp_pause) + ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); + + /* find a key slot to give this thread ID and store a + * pointer to our keys there; start at the thread ID + * itself (mod LDAP_MAXTHR) and look for an empty slot. + */ + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + for (keyslot = hash & (LDAP_MAXTHR-1); + (kctx = thread_keys[keyslot].ctx) && kctx != DELETED_THREAD_CTX; + keyslot = (keyslot+1) & (LDAP_MAXTHR-1)); + thread_keys[keyslot].ctx = &ctx; + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); + + pool->ltp_starting--; + + for (;;) { + while (pool->ltp_pause) + ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); + + if (pool->ltp_state == LDAP_INT_THREAD_POOL_STOPPING) + break; + + task = LDAP_STAILQ_FIRST(&pool->ltp_pending_list); + if (task == NULL) { if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING) break; - if (pool->ltp_max_count > 0 - && pool->ltp_open_count > pool->ltp_max_count) + + if (pool->ltp_open_count > + (pool->ltp_max_count ? pool->ltp_max_count : LDAP_MAXTHR)) { /* too many threads running (can happen if the * maximum threads value is set during ongoing @@ -680,53 +595,41 @@ ldap_int_thread_pool_wrapper ( * always have at least one thread open). the check * should be like this: * if (pool->ltp_open_count > 1 && pool->ltp_starting == 0) - * check timer, leave thread (break;) + * check timer, wait if ltp_pause, leave thread (break;) * * Just use pthread_cond_timedwait if we want to * check idle time. */ - if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING - || pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) - { - ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); - } - + assert(pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING); + ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); continue; } + LDAP_STAILQ_REMOVE_HEAD(&pool->ltp_pending_list, ltt_next.q); pool->ltp_pending_count--; - - LDAP_SLIST_INSERT_HEAD(&pool->ltp_active_list, ctx, ltc_next.al); pool->ltp_active_count++; ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); - ctx->ltc_start_routine(&uctx, ctx->ltc_arg); + task->ltt_start_routine(&ctx, task->ltt_arg); -#ifdef LDAP_PVT_THREAD_POOL_SEM_LOAD_CONTROL - ldap_lazy_sem_post( thread_pool_sem ); -#endif ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); - LDAP_SLIST_REMOVE(&pool->ltp_active_list, ctx, - ldap_int_thread_ctx_s, ltc_next.al); - LDAP_SLIST_INSERT_HEAD(&pool->ltp_free_list, ctx, ltc_next.l); + LDAP_SLIST_INSERT_HEAD(&pool->ltp_free_list, task, ltt_next.l); pool->ltp_active_count--; - - if (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) { - if (pool->ltp_active_count < 2) { - ldap_pvt_thread_cond_signal(&pool->ltp_pcond); - } - ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); - } + /* let pool_pause know when it is the sole active thread */ + if (pool->ltp_active_count < 2) + ldap_pvt_thread_cond_signal(&pool->ltp_pcond); } - ldap_pvt_thread_pool_context_reset(&uctx); + /* The ltp_mutex lock protects ctx->ltu_key from pool_purgekey() + * during this call, since it prevents new pauses. */ + ldap_pvt_thread_pool_context_reset(&ctx); - thread_keys[keyslot].ctx = NULL; - thread_keys[keyslot].id = tid_zero; + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + thread_keys[keyslot].ctx = DELETED_THREAD_CTX; + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); pool->ltp_open_count--; - /* let pool_destroy know we're all done */ if (pool->ltp_open_count < 1) ldap_pvt_thread_cond_signal(&pool->ltp_cond); @@ -737,6 +640,7 @@ ldap_int_thread_pool_wrapper ( return(NULL); } +/* Pause the pool. Return when all other threads are paused. */ int ldap_pvt_thread_pool_pause ( ldap_pvt_thread_pool_t *tpool ) @@ -754,22 +658,30 @@ ldap_pvt_thread_pool_pause ( ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); /* If someone else has already requested a pause, we have to wait */ - while (pool->ltp_state == LDAP_INT_THREAD_POOL_PAUSING) { + if (pool->ltp_pause) { pool->ltp_pending_count++; pool->ltp_active_count--; - ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); + /* let the other pool_pause() know when it can proceed */ + if (pool->ltp_active_count < 2) + ldap_pvt_thread_cond_signal(&pool->ltp_pcond); + do { + ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex); + } while (pool->ltp_pause); pool->ltp_pending_count--; pool->ltp_active_count++; } - /* Wait for everyone else to finish */ - pool->ltp_state = LDAP_INT_THREAD_POOL_PAUSING; + + /* Wait for everyone else to pause or finish */ + pool->ltp_pause = 1; while (pool->ltp_active_count > 1) { ldap_pvt_thread_cond_wait(&pool->ltp_pcond, &pool->ltp_mutex); } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(0); } +/* End a pause */ int ldap_pvt_thread_pool_resume ( ldap_pvt_thread_pool_t *tpool ) @@ -785,13 +697,15 @@ ldap_pvt_thread_pool_resume ( return(0); ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); - - pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING; + pool->ltp_pause = 0; ldap_pvt_thread_cond_broadcast(&pool->ltp_cond); ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); return(0); } +/* + * Get the key's data and optionally free function in the given context. + */ int ldap_pvt_thread_pool_getkey( void *xctx, void *key, @@ -801,7 +715,7 @@ int ldap_pvt_thread_pool_getkey( ldap_int_thread_userctx_t *ctx = xctx; int i; - if ( !ctx || !data ) return EINVAL; + if ( !ctx || !key || !data ) return EINVAL; for ( i=0; iltu_key[i].ltk_key; i++ ) { if ( ctx->ltu_key[i].ltk_key == key ) { @@ -813,6 +727,23 @@ int ldap_pvt_thread_pool_getkey( return ENOENT; } +static void +clear_key_idx( ldap_int_thread_userctx_t *ctx, int i ) +{ + for ( ; i < MAXKEYS-1 && ctx->ltu_key[i+1].ltk_key; i++ ) + ctx->ltu_key[i] = ctx->ltu_key[i+1]; + ctx->ltu_key[i].ltk_key = NULL; +} + +/* + * Set or remove data for the key in the given context. + * key can be any unique pointer. + * kfree() is an optional function to free the data (but not the key): + * pool_context_reset() and pool_purgekey() call kfree(key, data), + * but pool_setkey() does not. For pool_setkey() it is the caller's + * responsibility to free any existing data with the same key. + * kfree() must not call functions taking a tpool argument. + */ int ldap_pvt_thread_pool_setkey( void *xctx, void *key, @@ -820,19 +751,30 @@ int ldap_pvt_thread_pool_setkey( ldap_pvt_thread_pool_keyfree_t *kfree ) { ldap_int_thread_userctx_t *ctx = xctx; - int i; + int i, found; if ( !ctx || !key ) return EINVAL; - for ( i=0; iltu_key[i].ltk_key || ctx->ltu_key[i].ltk_key == key ) { - ctx->ltu_key[i].ltk_key = key; - ctx->ltu_key[i].ltk_data = data; - ctx->ltu_key[i].ltk_free = kfree; - return 0; + for ( i=found=0; iltu_key[i].ltk_key == key ) { + found = 1; + break; + } else if ( !ctx->ltu_key[i].ltk_key ) { + break; } } - return ENOMEM; + + if ( data || kfree ) { + if ( i>=MAXKEYS ) + return ENOMEM; + ctx->ltu_key[i].ltk_key = key; + ctx->ltu_key[i].ltk_data = data; + ctx->ltu_key[i].ltk_free = kfree; + } else if ( found ) { + clear_key_idx( ctx, i ); + } + + return 0; } /* Free all elements with this key, no matter which thread they're in. @@ -843,16 +785,17 @@ void ldap_pvt_thread_pool_purgekey( void *key ) int i, j; ldap_int_thread_userctx_t *ctx; + assert ( key != NULL ); + for ( i=0; iltu_key[j].ltk_key; j++ ) { if ( ctx->ltu_key[j].ltk_key == key ) { if (ctx->ltu_key[j].ltk_free) ctx->ltu_key[j].ltk_free( ctx->ltu_key[j].ltk_key, ctx->ltu_key[j].ltk_data ); - ctx->ltu_key[j].ltk_key = NULL; - ctx->ltu_key[j].ltk_free = NULL; + clear_key_idx( ctx, j ); break; } } @@ -861,6 +804,7 @@ void ldap_pvt_thread_pool_purgekey( void *key ) } /* + * Find the context of the current thread. * This is necessary if the caller does not have access to the * thread context handle (for example, a slapd plugin calling * slapi_search_internal()). No doubt it is more efficient @@ -870,21 +814,35 @@ void ldap_pvt_thread_pool_purgekey( void *key ) void *ldap_pvt_thread_pool_context( ) { ldap_pvt_thread_t tid; - int i, hash; + unsigned i, hash; + ldap_int_thread_userctx_t *ctx; tid = ldap_pvt_thread_self(); - if ( ldap_pvt_thread_equal( tid, ldap_int_main_tid )) + if ( ldap_pvt_thread_equal( tid, ldap_int_main_thrctx.ltu_id )) return &ldap_int_main_thrctx; TID_HASH( tid, hash ); - for (i = hash & (LDAP_MAXTHR-1); - !ldap_pvt_thread_equal(thread_keys[i].id, tid_zero) && - !ldap_pvt_thread_equal(thread_keys[i].id, tid); - i = (i+1) & (LDAP_MAXTHR-1)); + i = hash &= (LDAP_MAXTHR-1); + ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); + do { + ctx = thread_keys[i].ctx; + if ( ctx == DELETED_THREAD_CTX ) + continue; + if ( !ctx || ldap_pvt_thread_equal(thread_keys[i].ctx->ltu_id, tid) ) + goto done; + } while ( (i = (i+1) & (LDAP_MAXTHR-1)) != hash ); + ctx = NULL; + done: + ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); - return thread_keys[i].ctx; + return ctx; } +/* + * Free the context's keys. + * Must not call functions taking a tpool argument (because this + * thread already holds ltp_mutex when called from pool_wrapper()). + */ void ldap_pvt_thread_pool_context_reset( void *vctx ) { ldap_int_thread_userctx_t *ctx = vctx; diff --git a/libraries/liblutil/detach.c b/libraries/liblutil/detach.c index 603c9ae2ae..eacd3fefec 100644 --- a/libraries/liblutil/detach.c +++ b/libraries/liblutil/detach.c @@ -56,7 +56,7 @@ lutil_detach( int debug, int do_close ) #ifdef HAVE_SYSCONF nbits = sysconf( _SC_OPEN_MAX ); -#elif HAVE_GETDTABLESIZE +#elif defined(HAVE_GETDTABLESIZE) nbits = getdtablesize(); #else nbits = FD_SETSIZE; @@ -70,7 +70,7 @@ lutil_detach( int debug, int do_close ) if ( debug == 0 ) { for ( i = 0; i < 5; i++ ) { -#if HAVE_THR +#ifdef HAVE_THR switch ( fork1() ) #else switch ( fork() ) diff --git a/libraries/liblutil/getpass.c b/libraries/liblutil/getpass.c index a6cf7404fd..607f36eeef 100644 --- a/libraries/liblutil/getpass.c +++ b/libraries/liblutil/getpass.c @@ -60,7 +60,7 @@ char * lutil_getpass( const char *prompt ) { -#if !defined(HAVE_POSIX_TERMIOS) && !defined(HAVE_SGTTY_H) +#if !defined(HAVE_TERMIOS_H) && !defined(HAVE_SGTTY_H) static char buf[256]; int i, c; diff --git a/libraries/liblutil/getpeereid.c b/libraries/liblutil/getpeereid.c index 97d87982ab..a128423036 100644 --- a/libraries/liblutil/getpeereid.c +++ b/libraries/liblutil/getpeereid.c @@ -28,6 +28,14 @@ #include #endif +#ifdef LDAP_PF_LOCAL_SENDMSG +#include +#ifdef HAVE_SYS_UIO_H +#include +#endif +#include +#endif + #ifdef HAVE_SYS_UCRED_H #ifdef HAVE_GRP_H #include /* for NGROUPS on Tru64 5.1 */ @@ -35,21 +43,13 @@ #include #endif -#if !defined(HAVE_GETPEERUCRED) && \ - !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ - defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ - defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) -#define DO_SENDMSG -#ifdef HAVE_SYS_UIO_H -#include -#endif -#include -#endif - #include - -int getpeereid( int s, uid_t *euid, gid_t *egid ) +int lutil_getpeereid( int s, uid_t *euid, gid_t *egid +#ifdef LDAP_PF_LOCAL_SENDMSG + , struct berval *peerbv +#endif + ) { #ifdef LDAP_PF_LOCAL #if defined( HAVE_GETPEERUCRED ) @@ -62,7 +62,7 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) #elif defined( SO_PEERCRED ) struct ucred peercred; - socklen_t peercredlen = sizeof peercred; + ber_socklen_t peercredlen = sizeof peercred; if(( getsockopt( s, SOL_SOCKET, SO_PEERCRED, (void *)&peercred, &peercredlen ) == 0 ) @@ -75,7 +75,7 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) #elif defined( LOCAL_PEERCRED ) struct xucred peercred; - socklen_t peercredlen = sizeof peercred; + ber_socklen_t peercredlen = sizeof peercred; if(( getsockopt( s, LOCAL_PEERCRED, 1, (void *)&peercred, &peercredlen ) == 0 ) @@ -85,9 +85,8 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) *egid = peercred.cr_gid; return 0; } -#elif defined( DO_SENDMSG ) - char dummy[8]; - int err, fd[2]; +#elif defined( LDAP_PF_LOCAL_SENDMSG ) && defined( MSG_WAITALL ) + int err, fd; struct iovec iov; struct msghdr msg = {0}; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL @@ -97,52 +96,68 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) # ifndef CMSG_LEN # define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) # endif - union { + struct { struct cmsghdr cm; - unsigned char control[CMSG_SPACE(sizeof(int))]; - } control_un; + int fd; + } control_st; struct cmsghdr *cmsg; # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */ struct stat st; + struct sockaddr_un lname, rname; + ber_socklen_t llen, rlen; - msg.msg_name = NULL; - msg.msg_namelen = 0; + rlen = sizeof(rname); + llen = sizeof(lname); + memset( &lname, 0, sizeof( lname )); + getsockname(s, (struct sockaddr *)&lname, &llen); - iov.iov_base = dummy; - iov.iov_len = sizeof dummy; + iov.iov_base = peerbv->bv_val; + iov.iov_len = peerbv->bv_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; + peerbv->bv_len = 0; + # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof( control_un.control ); + msg.msg_control = &control_st; + msg.msg_controllen = sizeof( struct cmsghdr ) + sizeof( int ); /* no padding! */ cmsg = CMSG_FIRSTHDR( &msg ); +# else + msg.msg_accrights = (char *)&fd; + msg.msg_accrightslen = sizeof(fd); +# endif /* * AIX returns a bogus file descriptor if recvmsg() is * called with MSG_PEEK (is this a bug?). Hence we need * to receive the Abandon PDU. */ - if( recvmsg( s, &msg, MSG_WAITALL ) >= 0 && + err = recvmsg( s, &msg, MSG_WAITALL ); + if( err >= 0 && +# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) && cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS ) + cmsg->cmsg_type == SCM_RIGHTS # else - msg.msg_accrights = (char *)fd; - msg.msg_accrightslen = sizeof(fd); - if( recvmsg( s, &msg, MSG_PEEK) >= 0 && msg.msg_accrightslen == sizeof(int) ) + msg.msg_accrightslen == sizeof(int) # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/ - { + ) { + int mode = S_IFIFO|S_ISUID|S_IRWXU; + /* We must receive a valid descriptor, it must be a pipe, - * and it must only be accessible by its owner. + * it must only be accessible by its owner, and it must + * have the name of our socket written on it. */ + peerbv->bv_len = err; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL - fd[0] = (*(int *)CMSG_DATA( cmsg )); + fd = (*(int *)CMSG_DATA( cmsg )); # endif - err = fstat( fd[0], &st ); - close(fd[0]); - if( err == 0 && S_ISFIFO(st.st_mode) && - ((st.st_mode & (S_IRWXG|S_IRWXO)) == 0)) + err = fstat( fd, &st ); + if ( err == 0 ) + rlen = read(fd, &rname, rlen); + close(fd); + if( err == 0 && st.st_mode == mode && + llen == rlen && !memcmp(&lname, &rname, llen)) { *euid = st.st_uid; *egid = st.st_gid; @@ -151,7 +166,7 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) } #elif defined(SOCKCREDSIZE) struct msghdr msg; - socklen_t crmsgsize; + ber_socklen_t crmsgsize; void *crmsg; struct cmsghdr *cmp; struct sockcred *sc; diff --git a/libraries/liblutil/ldif.c b/libraries/liblutil/ldif.c index 2af75fb732..482a604d62 100644 --- a/libraries/liblutil/ldif.c +++ b/libraries/liblutil/ldif.c @@ -865,6 +865,9 @@ ldif_read_record( fp2 = ldif_open_url( ptr ); if ( fp2 ) { LDIFFP *lnew = ber_memalloc( sizeof( LDIFFP )); + if ( lnew == NULL ) { + return 0; + } lnew->prev = lfp->prev; lnew->fp = lfp->fp; lfp->prev = lnew; diff --git a/libraries/liblutil/lockf.c b/libraries/liblutil/lockf.c index b808e6abdb..00d91dfb2f 100644 --- a/libraries/liblutil/lockf.c +++ b/libraries/liblutil/lockf.c @@ -33,12 +33,12 @@ #undef LOCK_API -#if HAVE_LOCKF && defined(F_LOCK) +#if defined(HAVE_LOCKF) && defined(F_LOCK) # define USE_LOCKF 1 # define LOCK_API "lockf" #endif -#if !defined(LOCK_API) && HAVE_FCNTL +#if !defined(LOCK_API) && defined(HAVE_FCNTL) # ifdef HAVE_FCNTL_H # include # endif @@ -48,8 +48,8 @@ # endif #endif -#if !defined(LOCK_API) && HAVE_FLOCK -# if HAVE_SYS_FILE_H +#if !defined(LOCK_API) && defined(HAVE_FLOCK) +# ifdef HAVE_SYS_FILE_H # include # endif # define USE_FLOCK 1 diff --git a/libraries/liblutil/passfile.c b/libraries/liblutil/passfile.c index c84cda7367..c6d9ff4163 100644 --- a/libraries/liblutil/passfile.c +++ b/libraries/liblutil/passfile.c @@ -44,7 +44,7 @@ lutil_get_filed_password( } passwd->bv_val = NULL; - passwd->bv_len = 4196; + passwd->bv_len = 4096; #ifdef HAVE_FSTAT { @@ -56,7 +56,8 @@ lutil_get_filed_password( filename ); } - passwd->bv_len = sb.st_size; + if ( sb.st_size ) + passwd->bv_len = sb.st_size; } } #endif /* HAVE_FSTAT */ diff --git a/libraries/liblutil/sasl.c b/libraries/liblutil/sasl.c index ffbd29846e..50b5a29ddc 100644 --- a/libraries/liblutil/sasl.c +++ b/libraries/liblutil/sasl.c @@ -49,6 +49,8 @@ lutil_sasl_freedefs( void *defaults ) { lutilSASLdefaults *defs = defaults; + + assert( defs != NULL ); if (defs->mech) ber_memfree(defs->mech); if (defs->realm) ber_memfree(defs->realm); diff --git a/libraries/liblutil/sockpair.c b/libraries/liblutil/sockpair.c index c2e6220035..308a758224 100644 --- a/libraries/liblutil/sockpair.c +++ b/libraries/liblutil/sockpair.c @@ -35,7 +35,8 @@ int lutil_pair( ber_socket_t sds[2] ) return pipe( sds ); #else struct sockaddr_in si; - int rc, len = sizeof(si); + int rc; + ber_socklen_t len = sizeof(si); ber_socket_t sd; sd = socket( AF_INET, SOCK_DGRAM, 0 ); diff --git a/libraries/liblutil/uuid.c b/libraries/liblutil/uuid.c index e2bbe74ad6..b5d4f6e68a 100644 --- a/libraries/liblutil/uuid.c +++ b/libraries/liblutil/uuid.c @@ -41,6 +41,8 @@ #ifdef HAVE_UUID_TO_STR # include +#elif defined( HAVE_UUID_GENERATE ) +# include #elif defined( _WIN32 ) # include #else @@ -56,7 +58,7 @@ #include /* not needed for Windows */ -#if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32) +#if !defined(HAVE_UUID_TO_STR) && !defined(HAVE_UUID_GENERATE) && !defined(_WIN32) static unsigned char * lutil_eaddr( void ) { @@ -251,7 +253,7 @@ mul64ll(unsigned long i1, unsigned long i2) #endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */ -#endif /* !HAVE_UUID_TO_STR && !_WIN32 */ +#endif /* !HAVE_UUID_TO_STR && !HAVE_UUID_GENERATE && !_WIN32 */ /* ** All we really care about is an ISO UUID string. The format of a UUID is: @@ -298,6 +300,13 @@ lutil_uuidstr( char *buf, size_t len ) return l; +#elif defined( HAVE_UUID_GENERATE ) + uuid_t uu; + + uuid_generate( uu ); + uuid_unparse_lower( uu, buf ); + return strlen( buf ); + #elif defined( _WIN32 ) UUID uuid; unsigned char *uuidstr; @@ -371,6 +380,47 @@ lutil_uuidstr( char *buf, size_t len ) #endif } +int +lutil_uuidstr_from_normalized( + char *uuid, + size_t uuidlen, + char *buf, + size_t buflen ) +{ + unsigned char nibble; + int i, d = 0; + + assert( uuid != NULL ); + assert( buf != NULL ); + + if ( uuidlen != 16 ) return -1; + if ( buflen < 36 ) return -1; + + for ( i = 0; i < 16; i++ ) { + if ( i == 4 || i == 6 || i == 8 || i == 10 ) { + buf[(i<<1)+d] = '-'; + d += 1; + } + + nibble = (uuid[i] >> 4) & 0xF; + if ( nibble < 10 ) { + buf[(i<<1)+d] = nibble + '0'; + } else { + buf[(i<<1)+d] = nibble - 10 + 'a'; + } + + nibble = (uuid[i]) & 0xF; + if ( nibble < 10 ) { + buf[(i<<1)+d+1] = nibble + '0'; + } else { + buf[(i<<1)+d+1] = nibble - 10 + 'a'; + } + } + + if ( buflen > 36 ) buf[36] = '\0'; + return 36; +} + #ifdef TEST int main(int argc, char **argv) diff --git a/servers/Makefile.in b/servers/Makefile.in index 4fc47ae36a..010cca46ca 100644 --- a/servers/Makefile.in +++ b/servers/Makefile.in @@ -13,5 +13,5 @@ ## top-level directory of the distribution or, alternatively, at ## . -SUBDIRS= slapd slurpd +SUBDIRS= slapd diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index e19e739a8f..fcc9a4ce83 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -29,7 +29,7 @@ SRCS = main.c globals.c bconfig.c config.c daemon.c \ dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \ value.c ava.c bind.c unbind.c abandon.c filterentry.c \ phonetic.c acl.c str2filter.c aclparse.c init.c user.c \ - repl.c lock.c controls.c extended.c passwd.c \ + lock.c controls.c extended.c passwd.c \ schema.c schema_check.c schema_init.c schema_prep.c \ schemaparse.c ad.c at.c mr.c syntax.c oc.c saslauthz.c \ oidm.c starttls.c index.c sets.c referral.c root_dse.c \ @@ -47,7 +47,7 @@ OBJS = main.o globals.o bconfig.o config.o daemon.o \ dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \ value.o ava.o bind.o unbind.o abandon.o filterentry.o \ phonetic.o acl.o str2filter.o aclparse.o init.o user.o \ - repl.o lock.o controls.o extended.o passwd.o \ + lock.o controls.o extended.o passwd.o \ schema.o schema_check.o schema_init.o schema_prep.o \ schemaparse.o ad.o at.o mr.o syntax.o oc.o saslauthz.o \ oidm.o starttls.o index.o sets.o referral.o root_dse.o \ diff --git a/servers/slapd/abandon.c b/servers/slapd/abandon.c index bd09f3e811..c77dc1e25e 100644 --- a/servers/slapd/abandon.c +++ b/servers/slapd/abandon.c @@ -37,7 +37,8 @@ do_abandon( Operation *op, SlapReply *rs ) ber_int_t id; Operation *o; - Debug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_abandon\n", + op->o_log_prefix, 0, 0 ); /* * Parse the abandon request. It looks like this: @@ -46,7 +47,8 @@ do_abandon( Operation *op, SlapReply *rs ) */ if ( ber_scanf( op->o_ber, "i", &id ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_abandon: ber_scanf failed\n", 0, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_abandon: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } @@ -55,15 +57,17 @@ do_abandon( Operation *op, SlapReply *rs ) op->o_log_prefix, (long) id, 0, 0, 0 ); if( get_ctrls( op, rs, 0 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_abandon: get_ctrls failed\n", 0, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_abandon: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); return rs->sr_err; } - Debug( LDAP_DEBUG_ARGS, "do_abandon: id=%ld\n", (long) id, 0 ,0 ); + Debug( LDAP_DEBUG_ARGS, "%s do_abandon: id=%ld\n", + op->o_log_prefix, (long) id, 0 ); if( id <= 0 ) { - Debug( LDAP_DEBUG_ANY, - "do_abandon: bad msgid %ld\n", (long) id, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_abandon: bad msgid %ld\n", + op->o_log_prefix, (long) id, 0 ); return LDAP_SUCCESS; } @@ -91,7 +95,7 @@ do_abandon( Operation *op, SlapReply *rs ) LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) { if ( o->o_msgid == id ) { LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops, - o, slap_op, o_next ); + o, Operation, o_next ); LDAP_STAILQ_NEXT(o, o_next) = NULL; op->o_conn->c_n_ops_pending--; slap_op_free( o ); @@ -102,8 +106,9 @@ do_abandon( Operation *op, SlapReply *rs ) ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); - Debug( LDAP_DEBUG_TRACE, "do_abandon: op=%ld %sfound\n", - (long) id, o ? "" : "not ", 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_abandon: op=%ld %sfound\n", + op->o_log_prefix, + (long) id, o ? "" : "not " ); return rs->sr_err; } diff --git a/servers/slapd/aci.c b/servers/slapd/aci.c index a86e3acd1f..ac786ace75 100644 --- a/servers/slapd/aci.c +++ b/servers/slapd/aci.c @@ -676,6 +676,7 @@ aci_init( void ) static slap_syntax_defs_rec aci_syntax_def = { "( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )", SLAP_SYNTAX_HIDE, + NULL, OpenLDAPaciValidate, OpenLDAPaciPretty }; diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 59478d83a6..14cc43894f 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -304,7 +304,7 @@ fe_access_allowed( be_orig = op->o_bd; if ( op->o_bd == NULL ) { - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd == NULL ) op->o_bd = frontendDB; } @@ -2053,7 +2053,7 @@ acl_set_cb_gather( Operation *op, SlapReply *rs ) } } - if ( bvals ) { + if ( bvalsp ) { p->bvals = slap_set_join( p->cookie, p->bvals, ( '|' | SLAP_SET_RREF ), bvalsp ); } @@ -2111,7 +2111,7 @@ acl_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *de goto url_done; } - op2.o_bd = select_backend( &op2.o_req_ndn, 0, 1 ); + op2.o_bd = select_backend( &op2.o_req_ndn, 1 ); if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) { rc = LDAP_NO_SUCH_OBJECT; goto url_done; diff --git a/servers/slapd/ad.c b/servers/slapd/ad.c index a48c7bdc39..0e79845f37 100644 --- a/servers/slapd/ad.c +++ b/servers/slapd/ad.c @@ -58,7 +58,7 @@ typedef struct Attr_option { int prefix; /* NAME is a tag and range prefix */ } Attr_option; -static Attr_option lang_option = { { sizeof("lang-")-1, "lang-" }, 1 }; +static Attr_option lang_option = { BER_BVC("lang-"), 1 }; /* Options sorted by name, and number of options */ static Attr_option *options = &lang_option; @@ -213,8 +213,8 @@ int slap_bv2ad( *text = "zero length option is invalid"; return rtn; - } else if ( optlen == sizeof("binary")-1 && - strncasecmp( opt, "binary", sizeof("binary")-1 ) == 0 ) + } else if ( optlen == STRLENOF("binary") && + strncasecmp( opt, "binary", STRLENOF("binary") ) == 0 ) { /* binary option */ if( slap_ad_is_binary( &desc ) ) { @@ -356,10 +356,10 @@ done:; if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) { dlen = desc.ad_type->sat_cname.bv_len + 1; if (desc.ad_tags.bv_len) { - dlen += 1+desc.ad_tags.bv_len; + dlen += 1 + desc.ad_tags.bv_len; } - if( slap_ad_is_binary( &desc ) ) { - dlen += sizeof(";binary")+desc.ad_tags.bv_len; + if ( slap_ad_is_binary( &desc ) ) { + dlen += 1 + STRLENOF(";binary") + desc.ad_tags.bv_len; } } @@ -384,7 +384,7 @@ done:; lp = NULL; if( desc.ad_tags.bv_len ) { lp = desc.ad_tags.bv_val; - while( strncasecmp(lp, "binary", sizeof("binary")-1) < 0 + while( strncasecmp(lp, "binary", STRLENOF("binary")) < 0 && (lp = strchr( lp, ';' )) != NULL ) ++lp; if( lp != desc.ad_tags.bv_val ) { @@ -906,12 +906,14 @@ str2anlist( AttributeName *an, char *in, const char *brkstr ) } an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) ); - BER_BVZERO( &an[i + j].an_name ); anew = an + i; for ( s = ldap_pvt_strtok( str, brkstr, &lasts ); s != NULL; s = ldap_pvt_strtok( NULL, brkstr, &lasts ) ) { + /* put a stop mark */ + BER_BVZERO( &anew[1].an_name ); + anew->an_desc = NULL; anew->an_oc = NULL; anew->an_oc_exclude = 0; @@ -961,10 +963,8 @@ str2anlist( AttributeName *an, char *in, const char *brkstr ) return( an ); reterr: - for ( i = 0; an[i].an_name.bv_val; i++ ) { - free( an[i].an_name.bv_val ); - } - free( an ); + anlist_free( an, 1, NULL ); + /* * overwrites input string * on error! @@ -974,6 +974,24 @@ reterr: return NULL; } +void +anlist_free( AttributeName *an, int freename, void *ctx ) +{ + if ( an == NULL ) { + return; + } + + if ( freename ) { + int i; + + for ( i = 0; an[i].an_name.bv_val; i++ ) { + ber_memfree_x( an[i].an_name.bv_val, ctx ); + } + } + + ber_memfree_x( an, ctx ); +} + char **anlist2charray_x( AttributeName *an, int dup, void *ctx ) { char **attrs; @@ -1131,7 +1149,7 @@ file2anlist( AttributeName *an, const char *fname, const char *brkstr ) } an = str2anlist( an, line, brkstr ); if ( an == NULL ) - return NULL; + break; lcur = line; } ch_free( line ); diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 8d22d54afc..280fb4f20f 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -49,7 +49,9 @@ do_add( Operation *op, SlapReply *rs ) int rc = 0; int freevals = 1; - Debug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_add\n", + op->o_log_prefix, 0, 0 ); + /* * Parse the add request. It looks like this: * @@ -64,26 +66,14 @@ do_add( Operation *op, SlapReply *rs ) /* get the name */ if ( ber_scanf( ber, "{m", /*}*/ &dn ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } - op->ora_e = entry_alloc(); - - rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, - op->o_tmpmemctx ); - - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_add: invalid dn (%s)\n", dn.bv_val, 0, 0 ); - send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); - goto done; - } - - ber_dupbv( &op->ora_e->e_name, &op->o_req_dn ); - ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn ); - - Debug( LDAP_DEBUG_ARGS, "do_add: dn (%s)\n", op->ora_e->e_dn, 0, 0 ); + Debug( LDAP_DEBUG_ARGS, "%s do_add: dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); /* get the attrs */ for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT; @@ -97,15 +87,16 @@ do_add( Operation *op, SlapReply *rs ) rtag = ber_scanf( ber, "{m{W}}", &tmp.sml_type, &tmp.sml_values ); if ( rtag == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_add: decoding error\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_add: decoding error\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto done; } if ( tmp.sml_values == NULL ) { - Debug( LDAP_DEBUG_ANY, "no values for type %s\n", - tmp.sml_type.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_add: no values for type %s\n", + op->o_log_prefix, tmp.sml_type.bv_val, 0 ); send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "no values for attribute type" ); goto done; @@ -125,26 +116,42 @@ do_add( Operation *op, SlapReply *rs ) } if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_add: ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto done; } if ( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_add: get_ctrls failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_add: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); goto done; } + rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, + op->o_tmpmemctx ); + + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "%s do_add: invalid dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); + send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); + goto done; + } + + op->ora_e = entry_alloc(); + ber_dupbv( &op->ora_e->e_name, &op->o_req_dn ); + ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn ); + + Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n", + op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); + if ( modlist == NULL ) { send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "no attributes provided" ); goto done; } - Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n", - op->o_log_prefix, op->ora_e->e_name.bv_val, 0, 0, 0 ); - if ( dn_match( &op->ora_e->e_nname, &slap_empty_bv ) ) { /* protocolError may be a more appropriate error */ send_ldap_error( op, rs, LDAP_ALREADY_EXISTS, @@ -220,21 +227,18 @@ done:; int fe_op_add( Operation *op, SlapReply *rs ) { - int manageDSAit; Modifications **modtail = &op->ora_modlist; int rc = 0; BackendDB *op_be, *bd = op->o_bd; char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); - manageDSAit = get_manageDSAit( op ); - /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - op->o_bd = select_backend( &op->ora_e->e_nname, manageDSAit, 1 ); + op->o_bd = select_backend( &op->ora_e->e_nname, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, @@ -257,7 +261,7 @@ fe_op_add( Operation *op, SlapReply *rs ) /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { - op->o_bd = select_backend( &op->ora_e->e_nname, manageDSAit, 0 ); + op->o_bd = select_backend( &op->ora_e->e_nname, 0 ); } /* check restrictions */ @@ -290,7 +294,6 @@ fe_op_add( Operation *op, SlapReply *rs ) int repl_user = be_isupdate( op ); if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; op->o_bd = op_be; @@ -322,9 +325,6 @@ fe_op_add( Operation *op, SlapReply *rs ) send_ldap_result( op, rs ); goto done; } - - cb.sc_next = op->o_callback; - op->o_callback = &cb; } rc = op->o_bd->be_add( op, rs ); diff --git a/servers/slapd/alock.c b/servers/slapd/alock.c index 37d467ad12..c7bb16d56f 100644 --- a/servers/slapd/alock.c +++ b/servers/slapd/alock.c @@ -32,7 +32,7 @@ #include #include #include -#if HAVE_SYS_FILE_H +#ifdef HAVE_SYS_FILE_H #include #endif #include diff --git a/servers/slapd/at.c b/servers/slapd/at.c index 4538f5b5d4..e70f10e969 100644 --- a/servers/slapd/at.c +++ b/servers/slapd/at.c @@ -74,7 +74,7 @@ struct aindexrec { static Avlnode *attr_index = NULL; static Avlnode *attr_cache = NULL; -static LDAP_STAILQ_HEAD(ATList, slap_attribute_type) attr_list +static LDAP_STAILQ_HEAD(ATList, AttributeType) attr_list = LDAP_STAILQ_HEAD_INITIALIZER(attr_list); /* Last hardcoded attribute registered */ @@ -253,7 +253,7 @@ at_delete( AttributeType *at ) { at->sat_flags |= SLAP_AT_DELETED; - LDAP_STAILQ_REMOVE(&attr_list,at,slap_attribute_type,sat_next); + LDAP_STAILQ_REMOVE(&attr_list, at, AttributeType, sat_next); at_delete_names( at ); } @@ -459,6 +459,7 @@ at_insert( /* Keep old oid, free new oid; * Keep old ads, free new ads; + * Keep old ad_mutex, free new ad_mutex; * Keep new everything else, free old */ tmp = *old_sat; @@ -467,6 +468,8 @@ at_insert( tmp.sat_oid = sat->sat_oid; old_sat->sat_ad = tmp.sat_ad; tmp.sat_ad = sat->sat_ad; + old_sat->sat_ad_mutex = tmp.sat_ad_mutex; + tmp.sat_ad_mutex = sat->sat_ad_mutex; *sat = tmp; /* Check for basic ad pointing at old cname */ @@ -751,9 +754,12 @@ at_add( goto error_return; } - if( sat->sat_syntax != NULL && sat->sat_syntax != syn ) { - code = SLAP_SCHERR_ATTR_BAD_SUP; - goto error_return; + if ( sat->sat_syntax != NULL && sat->sat_syntax != syn ) { + /* BEWARE: no loop detection! */ + if ( syn_is_sup( sat->sat_syntax, syn ) ) { + code = SLAP_SCHERR_ATTR_BAD_SUP; + goto error_return; + } } sat->sat_syntax = syn; diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index 4e418e3032..315442466f 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -185,9 +185,10 @@ comp_tree_free( Attribute *a ) void attrs_free( Attribute *a ) { - Attribute *b, *tail, *next; - if ( a ) { + Attribute *b = (Attribute *)0xBAD, *tail, *next; + + /* save tail */ tail = a; do { next = a->a_next; @@ -198,6 +199,8 @@ attrs_free( Attribute *a ) } while ( next ); ldap_pvt_thread_mutex_lock( &attr_mutex ); + /* replace NULL with current attr list and let attr list + * start from last attribute returned to list */ tail->a_next = attr_list; attr_list = b; ldap_pvt_thread_mutex_unlock( &attr_mutex ); diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index 1f70e8ef40..88f5feb533 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -35,7 +35,7 @@ bdb_add(Operation *op, SlapReply *rs ) DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo = {0}; int subentry; - u_int32_t locker = 0, rlocker = 0; + BDB_LOCKER locker = 0, rlocker = 0; DB_LOCK lock; int num_retries = 0; diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index d564bfedfc..51edd51c0b 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -58,6 +58,28 @@ LDAP_BEGIN_DECL #define BDB_PAGESIZE 4096 /* BDB's original default */ #endif +/* 4.6.18 redefines cursor->locker */ +#if DB_VERSION_FULL >= 0x04060012 + +struct __db_locker { + u_int32_t id; +}; + +typedef struct __db_locker * BDB_LOCKER; + +extern int __lock_getlocker(DB_LOCKTAB *lt, u_int32_t locker, int create, DB_LOCKER **ret); + +#define CURSOR_SETLOCKER(cursor, id) cursor->locker = id +#define CURSOR_GETLOCKER(cursor) cursor->locker +#else + +typedef u_int32_t BDB_LOCKER; + +#define CURSOR_SETLOCKER(cursor, id) cursor->locker = id +#define CURSOR_GETLOCKER(cursor) cursor->locker + +#endif + #define DEFAULT_CACHE_SIZE 1000 /* The default search IDL stack cache depth */ @@ -131,10 +153,11 @@ typedef struct bdb_cache { int c_maxsize; int c_cursize; int c_minfree; + int c_eimax; int c_eiused; /* EntryInfo's in use */ int c_leaves; /* EntryInfo leaf nodes */ int c_purging; - u_int32_t c_locker; /* used by lru cleaner */ + BDB_LOCKER c_locker; /* used by lru cleaner */ ldap_pvt_thread_rdwr_t c_rwlock; ldap_pvt_thread_mutex_t c_lru_mutex; ldap_pvt_thread_mutex_t c_count_mutex; @@ -208,6 +231,12 @@ struct bdb_info { char *bi_db_config_path; BerVarray bi_db_config; bdb_monitor_t bi_monitor; + +#ifdef BDB_MONITOR_IDX + ldap_pvt_thread_mutex_t bi_idx_mutex; + Avlnode *bi_idx; +#endif /* BDB_MONITOR_IDX */ + int bi_flags; #define BDB_IS_OPEN 0x01 #define BDB_HAS_CONFIG 0x02 @@ -223,6 +252,7 @@ struct bdb_info { #define bi_id2entry bi_databases[BDB_ID2ENTRY] #define bi_dn2id bi_databases[BDB_DN2ID] + struct bdb_lock_info { struct bdb_lock_info *bli_next; ID bli_id; @@ -232,14 +262,14 @@ struct bdb_lock_info { struct bdb_op_info { BackendDB* boi_bdb; DB_TXN* boi_txn; + BDB_LOCKER boi_locker; u_int32_t boi_err; - u_int32_t boi_locker; int boi_acl_cache; struct bdb_lock_info *boi_locks; /* used when no txn */ }; #define DB_OPEN(db, file, name, type, flags, mode) \ - (db)->open(db, file, name, type, flags, mode) + ((db)->open)(db, file, name, type, flags, mode) #if DB_VERSION_MAJOR < 4 #define LOCK_DETECT(env,f,t,a) lock_detect(env, f, t, a) @@ -270,7 +300,13 @@ struct bdb_op_info { #if DB_VERSION_FULL >= 0x04010011 #undef DB_OPEN #define DB_OPEN(db, file, name, type, flags, mode) \ - (db)->open(db, NULL, file, name, type, flags, mode) + ((db)->open)(db, NULL, file, name, type, flags, mode) +#endif + +/* BDB 4.6.18 makes locker a struct instead of an int */ +#if DB_VERSION_FULL >= 0x04060012 +#undef TXN_ID +#define TXN_ID(txn) (txn)->locker #endif #endif diff --git a/servers/slapd/back-bdb/bind.c b/servers/slapd/back-bdb/bind.c index 84f3a38a0e..3f6b37a908 100644 --- a/servers/slapd/back-bdb/bind.c +++ b/servers/slapd/back-bdb/bind.c @@ -32,19 +32,37 @@ bdb_bind( Operation *op, SlapReply *rs ) AttributeDescription *password = slap_schema.si_ad_userPassword; - u_int32_t locker; + BDB_LOCKER locker; DB_LOCK lock; Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_bind) ": dn: %s\n", op->o_req_dn.bv_val, 0, 0); +#ifdef LDAP_DEVEL /* allow noauth binds */ - if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op )) { - ber_dupbv( &op->oq_bind.rb_edn, be_root_dn( op->o_bd ) ); - /* front end will send result */ - return LDAP_SUCCESS; + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + /* in case of success, frontend will send result; + * otherwise, be_rootdn_bind() did */ + return rs->sr_err; + } + +#else /* traditional */ + /* allow noauth binds */ + switch ( be_rootdn_bind( op, NULL ) ) { + case LDAP_SUCCESS: + /* frontend will send result */ + return rs->sr_err; + + default: + /* give the database a chanche */ + break; } +#endif /* traditional */ rs->sr_err = LOCK_ID(bdb->bi_dbenv, &locker); switch(rs->sr_err) { diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index 7f93b3bad1..c6d48112ce 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -63,9 +63,9 @@ bdb_cache_entryinfo_new( Cache *cache ) if ( cache->c_eifree ) { ei = cache->c_eifree; cache->c_eifree = ei->bei_lrunext; + ei->bei_finders = 0; } ldap_pvt_thread_mutex_unlock( &cache->c_eifree_mutex ); - ei->bei_finders = 0; } if ( !ei ) { ei = ch_calloc(1, sizeof(EntryInfo)); @@ -155,11 +155,17 @@ bdb_cache_lru_link( struct bdb_info *bdb, EntryInfo *ei ) * alternatives though. */ +#if DB_VERSION_FULL >= 0x04060012 +#define BDB_LOCKID(locker) locker->id +#else +#define BDB_LOCKID(locker) locker +#endif + /* Atomically release and reacquire a lock */ int bdb_cache_entry_db_relock( struct bdb_info *bdb, - u_int32_t locker, + BDB_LOCKER locker, EntryInfo *ei, int rw, int tryOnly, @@ -183,7 +189,7 @@ bdb_cache_entry_db_relock( list[1].lock = *lock; list[1].mode = rw ? DB_LOCK_WRITE : DB_LOCK_READ; list[1].obj = &lockobj; - rc = bdb->bi_dbenv->lock_vec(bdb->bi_dbenv, locker, tryOnly ? DB_LOCK_NOWAIT : 0, + rc = bdb->bi_dbenv->lock_vec(bdb->bi_dbenv, BDB_LOCKID(locker), tryOnly ? DB_LOCK_NOWAIT : 0, list, 2, NULL ); if (rc && !tryOnly) { @@ -198,7 +204,7 @@ bdb_cache_entry_db_relock( } static int -bdb_cache_entry_db_lock( struct bdb_info *bdb, u_int32_t locker, EntryInfo *ei, +bdb_cache_entry_db_lock( struct bdb_info *bdb, BDB_LOCKER locker, EntryInfo *ei, int rw, int tryOnly, DB_LOCK *lock ) { #ifdef NO_DB_LOCK @@ -218,7 +224,7 @@ bdb_cache_entry_db_lock( struct bdb_info *bdb, u_int32_t locker, EntryInfo *ei, lockobj.data = &ei->bei_id; lockobj.size = sizeof(ei->bei_id) + 1; - rc = LOCK_GET(bdb->bi_dbenv, locker, tryOnly ? DB_LOCK_NOWAIT : 0, + rc = LOCK_GET(bdb->bi_dbenv, BDB_LOCKID(locker), tryOnly ? DB_LOCK_NOWAIT : 0, &lockobj, db_rw, lock); if (rc && !tryOnly) { Debug( LDAP_DEBUG_TRACE, @@ -457,7 +463,7 @@ int hdb_cache_find_parent( Operation *op, DB_TXN *txn, - u_int32_t locker, + BDB_LOCKER locker, ID id, EntryInfo **res ) { @@ -631,7 +637,7 @@ bdb_cache_lru_purge( struct bdb_info *bdb ) if ( slapMode & SLAP_TOOL_READONLY ) eimax = 0; else - eimax = bdb->bi_cache.c_maxsize * 4; + eimax = bdb->bi_cache.c_eimax; /* Look for an unused entry to remove */ for ( elru = bdb->bi_cache.c_lruhead; elru; elru = elnext ) { @@ -742,7 +748,7 @@ bdb_cache_find_id( ID id, EntryInfo **eip, int islocked, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; @@ -963,7 +969,7 @@ bdb_cache_add( EntryInfo *eip, Entry *e, struct berval *nrdn, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { EntryInfo *new, ei; @@ -1038,7 +1044,7 @@ bdb_cache_modify( struct bdb_info *bdb, Entry *e, Attribute *newAttrs, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { EntryInfo *ei = BEI(e); @@ -1068,7 +1074,7 @@ bdb_cache_modrdn( struct berval *nrdn, Entry *new, EntryInfo *ein, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { EntryInfo *ei = BEI(e), *pei; @@ -1163,7 +1169,7 @@ int bdb_cache_delete( struct bdb_info *bdb, Entry *e, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { EntryInfo *ei = BEI(e); @@ -1328,11 +1334,11 @@ bdb_lru_print( Cache *cache ) { EntryInfo *e; - fprintf( stderr, "LRU circle head: %p\n", cache->c_lruhead ); + fprintf( stderr, "LRU circle head: %p\n", (void *) cache->c_lruhead ); fprintf( stderr, "LRU circle (tail forward):\n" ); for ( e = cache->c_lrutail; ; ) { fprintf( stderr, "\t%p, %p id %ld rdn \"%s\"\n", - e, e->bei_e, e->bei_id, e->bei_nrdn.bv_val ); + (void *) e, (void *) e->bei_e, e->bei_id, e->bei_nrdn.bv_val ); e = e->bei_lrunext; if ( e == cache->c_lrutail ) break; @@ -1340,7 +1346,7 @@ bdb_lru_print( Cache *cache ) fprintf( stderr, "LRU circle (tail backward):\n" ); for ( e = cache->c_lrutail; ; ) { fprintf( stderr, "\t%p, %p id %ld rdn \"%s\"\n", - e, e->bei_e, e->bei_id, e->bei_nrdn.bv_val ); + (void *) e, (void *) e->bei_e, e->bei_id, e->bei_nrdn.bv_val ); e = e->bei_lruprev; if ( e == cache->c_lrutail ) break; @@ -1354,9 +1360,15 @@ static void bdb_locker_id_free( void *key, void *data ) { DB_ENV *env = key; - u_int32_t lockid = (long)data; + u_int32_t lockid; int rc; +#if DB_VERSION_FULL >= 0x04060012 + BDB_LOCKER lptr = data; + lockid = lptr->id; +#else + lockid = (long)data; +#endif rc = XLOCK_ID_FREE( env, lockid ); if ( rc == EINVAL ) { DB_LOCKREQ lr; @@ -1385,7 +1397,7 @@ bdb_locker_flush( DB_ENV *env ) } int -bdb_locker_id( Operation *op, DB_ENV *env, u_int32_t *locker ) +bdb_locker_id( Operation *op, DB_ENV *env, BDB_LOCKER *locker ) { int i, rc; u_int32_t lockid; @@ -1415,7 +1427,14 @@ bdb_locker_id( Operation *op, DB_ENV *env, u_int32_t *locker ) if ( rc != 0) { return rc; } +#if DB_VERSION_FULL >= 0x04060012 + { BDB_LOCKER lptr; + __lock_getlocker( env->lk_handle, lockid, 0, &lptr ); + data = lptr; + } +#else data = (void *)((long)lockid); +#endif if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, env, data, bdb_locker_id_free ) ) ) { XLOCK_ID_FREE( env, lockid ); @@ -1427,7 +1446,11 @@ bdb_locker_id( Operation *op, DB_ENV *env, u_int32_t *locker ) } else { lockid = (long)data; } +#if DB_VERSION_FULL >= 0x04060012 + *locker = data; +#else *locker = lockid; +#endif return 0; } #endif /* BDB_REUSE_LOCKERS */ diff --git a/servers/slapd/back-bdb/compare.c b/servers/slapd/back-bdb/compare.c index 4999ec7d46..972071314c 100644 --- a/servers/slapd/back-bdb/compare.c +++ b/servers/slapd/back-bdb/compare.c @@ -30,7 +30,7 @@ bdb_compare( Operation *op, SlapReply *rs ) Attribute *a; int manageDSAit = get_manageDSAit( op ); - u_int32_t locker; + BDB_LOCKER locker; DB_LOCK lock; rs->sr_err = LOCK_ID(bdb->bi_dbenv, &locker); diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c index 4d92f2f834..3895cf30c9 100644 --- a/servers/slapd/back-bdb/config.c +++ b/servers/slapd/back-bdb/config.c @@ -86,6 +86,11 @@ static ConfigTable bdbcfg[] = { "( OLcfgDbAt:1.5 NAME 'olcDbDirtyRead' " "DESC 'Allow reads of uncommitted data' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, + { "dncachesize", "size", 2, 2, 0, ARG_INT|ARG_OFFSET, + (void *)offsetof(struct bdb_info, bi_cache.c_eimax), + "( OLcfgDbAt:1.12 NAME 'olcDbDNcacheSize' " + "DESC 'DN cache size' " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "idlcachesize", "size", 2, 2, 0, ARG_INT|ARG_OFFSET, (void *)offsetof(struct bdb_info,bi_idl_cache_max_size), "( OLcfgDbAt:1.6 NAME 'olcDbIDLcacheSize' " @@ -140,7 +145,7 @@ static ConfigOCs bdbocs[] = { "olcDbNoSync $ olcDbDirtyRead $ olcDbIDLcacheSize $ " "olcDbIndex $ olcDbLinearIndex $ olcDbLockDetect $ " "olcDbMode $ olcDbSearchStack $ olcDbShmKey $ " - "olcDbCacheFree ) )", + "olcDbCacheFree $ olcDbDNcacheSize ) )", Cft_Database, bdbcfg }, { NULL, 0, NULL } }; @@ -179,19 +184,20 @@ bdb_online_index( void *ctx, void *arg ) Connection conn = {0}; OperationBuffer opbuf; - Operation *op = (Operation *) &opbuf; + Operation *op; DBC *curs; DBT key, data; DB_TXN *txn; DB_LOCK lock; - u_int32_t locker; + BDB_LOCKER locker; ID id, nid; EntryInfo *ei; int rc, getnext = 1; int i; - connection_fake_init( &conn, op, ctx ); + connection_fake_init( &conn, &opbuf, ctx ); + op = &opbuf.ob_op; op->o_bd = be; @@ -319,9 +325,9 @@ bdb_cf_cleanup( ConfigArgs *c ) if ( bdb->bi_flags & BDB_RE_OPEN ) { bdb->bi_flags ^= BDB_RE_OPEN; - rc = c->be->bd_info->bi_db_close( c->be ); + rc = c->be->bd_info->bi_db_close( c->be, NULL ); if ( rc == 0 ) - rc = c->be->bd_info->bi_db_open( c->be ); + rc = c->be->bd_info->bi_db_open( c->be, NULL ); /* If this fails, we need to restart */ if ( rc ) { slapd_shutdown = 2; @@ -472,7 +478,6 @@ bdb_cf_gen( ConfigArgs *c ) bdb->bi_db_config_path = NULL; c->cleanup = bdb_cf_cleanup; ldap_pvt_thread_pool_purgekey( bdb->bi_dbenv ); - ldap_pvt_thread_pool_purgekey( ((char *)bdb->bi_dbenv) + 1 ); break; case BDB_NOSYNC: bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC, 0 ); diff --git a/servers/slapd/back-bdb/dbcache.c b/servers/slapd/back-bdb/dbcache.c index 42f9f8b883..35529c7923 100644 --- a/servers/slapd/back-bdb/dbcache.c +++ b/servers/slapd/back-bdb/dbcache.c @@ -114,7 +114,7 @@ bdb_db_cache( rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); file = ch_malloc( strlen( name ) + sizeof(BDB_SUFFIX) ); - sprintf( file, "%s" BDB_SUFFIX, name ); + sprintf( file, "%s%s", name, BDB_SUFFIX ); #ifdef HAVE_EBCDIC __atoe( file ); diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index 37b7a13cc9..c9fdba93d6 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -38,7 +38,7 @@ bdb_delete( Operation *op, SlapReply *rs ) struct bdb_op_info opinfo = {0}; ID eid; - u_int32_t locker = 0; + BDB_LOCKER locker = 0; DB_LOCK lock, plock; int num_retries = 0; @@ -100,7 +100,7 @@ txnReturn: ctrls[num_ctrls] = 0; /* allocate CSN */ - if ( BER_BVISEMPTY( &op->o_csn )) { + if ( BER_BVISNULL( &op->o_csn ) ) { struct berval csn; char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; diff --git a/servers/slapd/back-bdb/dn2entry.c b/servers/slapd/back-bdb/dn2entry.c index 5211f8e9b8..9df6d4f6d3 100644 --- a/servers/slapd/back-bdb/dn2entry.c +++ b/servers/slapd/back-bdb/dn2entry.c @@ -34,7 +34,7 @@ bdb_dn2entry( struct berval *dn, EntryInfo **e, int matched, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ) { EntryInfo *ei = NULL; diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 07acfeb2d5..3f83cf4fc6 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -332,7 +332,7 @@ bdb_dn2id_children( int bdb_dn2idl( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, struct berval *ndn, EntryInfo *ei, ID *ids, @@ -712,7 +712,7 @@ int hdb_dn2id_parent( Operation *op, DB_TXN *txn, - u_int32_t locker, + BDB_LOCKER locker, EntryInfo *ei, ID *idp ) { @@ -738,7 +738,7 @@ hdb_dn2id_parent( rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; if ( !txn && locker ) { - cursor->locker = locker; + CURSOR_SETLOCKER(cursor, locker); } data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2); @@ -833,7 +833,7 @@ hdb_dn2id_children( struct dn2id_cookie { struct bdb_info *bdb; Operation *op; - u_int32_t locker; + BDB_LOCKER locker; EntryInfo *ei; ID *ids; ID *tmp; @@ -1064,7 +1064,7 @@ gotit: int hdb_dn2idl( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, struct berval *ndn, EntryInfo *ei, ID *ids, diff --git a/servers/slapd/back-bdb/filterindex.c b/servers/slapd/back-bdb/filterindex.c index e88395f784..cd41d4eacc 100644 --- a/servers/slapd/back-bdb/filterindex.c +++ b/servers/slapd/back-bdb/filterindex.c @@ -27,39 +27,39 @@ static int presence_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeDescription *desc, ID *ids ); static int equality_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp ); static int inequality_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp, int gtorlt ); static int approx_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp ); static int substring_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, SubstringsAssertion *sub, ID *ids, ID *tmp ); static int list_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, Filter *flist, int ftype, ID *ids, @@ -69,7 +69,7 @@ static int list_candidates( static int ext_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion *mra, ID *ids, ID *tmp, @@ -79,7 +79,7 @@ ext_candidates( static int comp_candidates ( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion *mra, ComponentFilter *f, ID *ids, @@ -89,7 +89,7 @@ comp_candidates ( static int ava_comp_candidates ( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, AttributeAliasing *aa, ID *ids, @@ -100,7 +100,7 @@ ava_comp_candidates ( int bdb_filter_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, Filter *f, ID *ids, ID *tmp, @@ -231,7 +231,7 @@ out: static int comp_list_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion* mra, ComponentFilter *flist, int ftype, @@ -296,7 +296,7 @@ comp_list_candidates( static int comp_equality_candidates ( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion *mra, ComponentAssertion *ca, ID *ids, @@ -344,9 +344,6 @@ comp_equality_candidates ( if( rc != LDAP_SUCCESS ) { return 0; } - if ( db == NULL ) { - return 0; - } if( !mr ) { return 0; @@ -410,7 +407,7 @@ comp_equality_candidates ( static int ava_comp_candidates ( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, AttributeAliasing *aa, ID *ids, @@ -434,7 +431,7 @@ ava_comp_candidates ( static int comp_candidates ( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion *mra, ComponentFilter *f, ID *ids, @@ -483,7 +480,7 @@ comp_candidates ( static int ext_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, MatchingRuleAssertion *mra, ID *ids, ID *tmp, @@ -562,7 +559,7 @@ ext_candidates( static int list_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, Filter *flist, int ftype, ID *ids, @@ -628,7 +625,7 @@ list_candidates( static int presence_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeDescription *desc, ID *ids ) { @@ -650,19 +647,19 @@ presence_candidates( rc = bdb_index_param( op->o_bd, desc, LDAP_FILTER_PRESENT, &db, &mask, &prefix ); - if( rc != LDAP_SUCCESS ) { + if( rc == LDAP_INAPPROPRIATE_MATCHING ) { + /* not indexed */ Debug( LDAP_DEBUG_TRACE, - "<= bdb_presence_candidates: (%s) index_param " - "returned=%d\n", - desc->ad_cname.bv_val, rc, 0 ); + "<= bdb_presence_candidates: (%s) not indexed\n", + desc->ad_cname.bv_val, 0, 0 ); return 0; } - if( db == NULL ) { - /* not indexed */ + if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "<= bdb_presence_candidates: (%s) not indexed\n", - desc->ad_cname.bv_val, 0, 0 ); + "<= bdb_presence_candidates: (%s) index_param " + "returned=%d\n", + desc->ad_cname.bv_val, rc, 0 ); return 0; } @@ -699,7 +696,7 @@ done: static int equality_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp ) @@ -721,18 +718,18 @@ equality_candidates( rc = bdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY, &db, &mask, &prefix ); - if( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_equality_candidates: (%s) " - "index_param failed (%d)\n", - ava->aa_desc->ad_cname.bv_val, rc, 0 ); + "<= bdb_equality_candidates: (%s) not indexed\n", + ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } - if ( db == NULL ) { + if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_equality_candidates: (%s) not indexed\n", - ava->aa_desc->ad_cname.bv_val, 0, 0 ); + "<= bdb_equality_candidates: (%s) " + "index_param failed (%d)\n", + ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } @@ -816,7 +813,7 @@ equality_candidates( static int approx_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp ) @@ -838,18 +835,18 @@ approx_candidates( rc = bdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_APPROX, &db, &mask, &prefix ); - if( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_approx_candidates: (%s) " - "index_param failed (%d)\n", - ava->aa_desc->ad_cname.bv_val, rc, 0 ); + "<= bdb_approx_candidates: (%s) not indexed\n", + ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } - if ( db == NULL ) { + if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_approx_candidates: (%s) not indexed\n", - ava->aa_desc->ad_cname.bv_val, 0, 0 ); + "<= bdb_approx_candidates: (%s) " + "index_param failed (%d)\n", + ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } @@ -936,7 +933,7 @@ approx_candidates( static int substring_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, SubstringsAssertion *sub, ID *ids, ID *tmp ) @@ -958,18 +955,18 @@ substring_candidates( rc = bdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS, &db, &mask, &prefix ); - if( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_substring_candidates: (%s) " - "index_param failed (%d)\n", - sub->sa_desc->ad_cname.bv_val, rc, 0 ); + "<= bdb_substring_candidates: (%s) not indexed\n", + sub->sa_desc->ad_cname.bv_val, 0, 0 ); return 0; } - if ( db == NULL ) { + if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_substring_candidates: (%s) not indexed\n", - sub->sa_desc->ad_cname.bv_val, 0, 0 ); + "<= bdb_substring_candidates: (%s) " + "index_param failed (%d)\n", + sub->sa_desc->ad_cname.bv_val, rc, 0 ); return 0; } @@ -1052,7 +1049,7 @@ substring_candidates( static int inequality_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, AttributeAssertion *ava, ID *ids, ID *tmp, @@ -1075,18 +1072,18 @@ inequality_candidates( rc = bdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY, &db, &mask, &prefix ); - if( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_inequality_candidates: (%s) " - "index_param failed (%d)\n", - ava->aa_desc->ad_cname.bv_val, rc, 0 ); + "<= bdb_inequality_candidates: (%s) not indexed\n", + ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } - if ( db == NULL ) { + if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "<= bdb_inequality_candidates: (%s) not indexed\n", - ava->aa_desc->ad_cname.bv_val, 0, 0 ); + "<= bdb_inequality_candidates: (%s) " + "index_param failed (%d)\n", + ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index 5c693c14a7..98c75bb9fa 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -93,7 +93,7 @@ int bdb_id2entry_update( int bdb_id2entry( BackendDB *be, DB_TXN *tid, - u_int32_t locker, + BDB_LOCKER locker, ID id, Entry **e ) { @@ -121,26 +121,27 @@ int bdb_id2entry( if ( rc ) return rc; /* Use our own locker if needed */ - if ( !tid && locker ) - cursor->locker = locker; + if ( !tid && locker ) { + CURSOR_SETLOCKER( cursor, locker ); + } /* Get the nattrs / nvals counts first */ data.ulen = data.dlen = sizeof(buf); data.data = buf; rc = cursor->c_get( cursor, &key, &data, DB_SET ); - if ( rc ) goto leave; + if ( rc ) goto finish; eh.bv.bv_val = buf; eh.bv.bv_len = data.size; rc = entry_header( &eh ); - if ( rc ) goto leave; + if ( rc ) goto finish; /* Get the size */ data.flags ^= DB_DBT_PARTIAL; data.ulen = 0; rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); - if ( rc != DB_BUFFER_SMALL ) goto leave; + if ( rc != DB_BUFFER_SMALL ) goto finish; /* Allocate a block and retrieve the data */ off = eh.data - eh.bv.bv_val; @@ -155,7 +156,7 @@ int bdb_id2entry( rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); -leave: +finish: cursor->c_close( cursor ); if( rc != 0 ) { @@ -317,7 +318,7 @@ int bdb_entry_get( int rc; const char *at_name = at ? at->ad_cname.bv_val : "(null)"; - u_int32_t locker = 0; + BDB_LOCKER locker = 0; DB_LOCK lock; int free_lock_id = 0; diff --git a/servers/slapd/back-bdb/idl.c b/servers/slapd/back-bdb/idl.c index c84486d790..35d6d4890d 100644 --- a/servers/slapd/back-bdb/idl.c +++ b/servers/slapd/back-bdb/idl.c @@ -480,7 +480,7 @@ int bdb_idl_fetch_key( BackendDB *be, DB *db, - u_int32_t locker, + BDB_LOCKER locker, DBT *key, ID *ids, DBC **saved_cursor, @@ -559,7 +559,7 @@ bdb_idl_fetch_key( "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } - cursor->locker = locker; + CURSOR_SETLOCKER( cursor, locker ); } else { cursor = *saved_cursor; } diff --git a/servers/slapd/back-bdb/index.c b/servers/slapd/back-bdb/index.c index 94d181de7e..e193dae30d 100644 --- a/servers/slapd/back-bdb/index.c +++ b/servers/slapd/back-bdb/index.c @@ -97,12 +97,32 @@ int bdb_index_param( { AttrInfo *ai; int rc; - slap_mask_t mask; + slap_mask_t mask, type = 0; DB *db; ai = index_mask( be, desc, prefixp ); - if( !ai ) { + if ( !ai ) { +#ifdef BDB_MONITOR_IDX + switch ( ftype ) { + case LDAP_FILTER_PRESENT: + type = SLAP_INDEX_PRESENT; + break; + case LDAP_FILTER_APPROX: + type = SLAP_INDEX_APPROX; + break; + case LDAP_FILTER_EQUALITY: + type = SLAP_INDEX_EQUALITY; + break; + case LDAP_FILTER_SUBSTRINGS: + type = SLAP_INDEX_SUBSTR; + break; + default: + return LDAP_INAPPROPRIATE_MATCHING; + } + bdb_monitor_idx_add( be->be_private, desc, type ); +#endif /* BDB_MONITOR_IDX */ + return LDAP_INAPPROPRIATE_MATCHING; } mask = ai->ai_indexmask; @@ -115,6 +135,7 @@ int bdb_index_param( switch( ftype ) { case LDAP_FILTER_PRESENT: + type = SLAP_INDEX_PRESENT; if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) { *prefixp = presence_key; goto done; @@ -122,6 +143,7 @@ int bdb_index_param( break; case LDAP_FILTER_APPROX: + type = SLAP_INDEX_APPROX; if ( desc->ad_type->sat_approx ) { if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) { goto done; @@ -133,12 +155,14 @@ int bdb_index_param( /* fall thru */ case LDAP_FILTER_EQUALITY: + type = SLAP_INDEX_EQUALITY; if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) { goto done; } break; case LDAP_FILTER_SUBSTRINGS: + type = SLAP_INDEX_SUBSTR; if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) { goto done; } @@ -148,6 +172,10 @@ int bdb_index_param( return LDAP_OTHER; } +#ifdef BDB_MONITOR_IDX + bdb_monitor_idx_add( be->be_private, desc, type ); +#endif /* BDB_MONITOR_IDX */ + return LDAP_INAPPROPRIATE_MATCHING; done: @@ -435,6 +463,10 @@ int bdb_index_recrun( AttrList *al; int i, rc = 0; + /* Never index ID 0 */ + if ( id == 0 ) + return 0; + for (i=base; ibi_nattrs; i+=slap_tool_thread_max) { ir = ir0 + i; if ( !ir->ai ) continue; @@ -472,6 +504,10 @@ bdb_index_entry( struct berval value = {0}; #endif + /* Never index ID 0 */ + if ( e->e_id == 0 ) + return 0; + Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n", opid == SLAP_INDEX_DELETE_OP ? "del" : "add", (long) e->e_id, e->e_dn ); diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index e4566c67be..01af4c2c46 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -26,6 +26,7 @@ #include #include #include "alock.h" +#include "config.h" static const struct bdbi_database { char *file; @@ -41,8 +42,12 @@ static const struct bdbi_database { typedef void * db_malloc(size_t); typedef void * db_realloc(void *, size_t); +#define bdb_db_init BDB_SYMBOL(db_init) +#define bdb_db_open BDB_SYMBOL(db_open) +#define bdb_db_close BDB_SYMBOL(db_close) + static int -bdb_db_init( BackendDB *be ) +bdb_db_init( BackendDB *be, ConfigReply *cr ) { struct bdb_info *bdb; int rc; @@ -79,15 +84,6 @@ bdb_db_init( BackendDB *be ) ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock ); ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock ); - { - Entry *e = entry_alloc(); - e->e_id = 0; - e->e_private = &bdb->bi_cache.c_dntree; - BER_BVSTR( &e->e_name, "" ); - BER_BVSTR( &e->e_nname, "" ); - bdb->bi_cache.c_dntree.bei_e = e; - } - be->be_private = bdb; be->be_cf_ocs = be->bd_info->bi_cf_ocs; @@ -97,10 +93,10 @@ bdb_db_init( BackendDB *be ) } static int -bdb_db_close( BackendDB *be ); +bdb_db_close( BackendDB *be, ConfigReply *cr ); static int -bdb_db_open( BackendDB *be ) +bdb_db_open( BackendDB *be, ConfigReply *cr ) { int rc, i; struct bdb_info *bdb = (struct bdb_info *) be->be_private; @@ -108,24 +104,28 @@ bdb_db_open( BackendDB *be ) u_int32_t flags; char path[MAXPATHLEN]; char *dbhome; + Entry *e = NULL; int do_recover = 0, do_alock_recover = 0; int alockt, quick = 0; if ( be->be_suffix == NULL ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: need suffix\n", - 0, 0, 0 ); + LDAP_XSTRING(bdb_db_open) ": need suffix\n", + 1, 0, 0 ); return -1; } Debug( LDAP_DEBUG_ARGS, - "bdb_db_open: %s\n", + LDAP_XSTRING(bdb_db_open) ": %s\n", be->be_suffix[0].bv_val, 0, 0 ); #ifndef BDB_MULTIPLE_SUFFIXES if ( be->be_suffix[1].bv_val ) { - Debug( LDAP_DEBUG_ANY, - "bdb_db_open: only one suffix allowed\n", 0, 0, 0 ); + if (cr) { + snprintf(cr->msg, sizeof(cr->msg), "only one suffix allowed"); + Debug( LDAP_DEBUG_ANY, + LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); + } return -1; } #endif @@ -134,9 +134,9 @@ bdb_db_open( BackendDB *be ) rc = stat( bdb->bi_dbenv_home, &stat1 ); if( rc !=0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: Cannot access database directory %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": Cannot access database directory %s (%d)\n", bdb->bi_dbenv_home, errno, 0 ); - return -1; + return -1; } /* Perform database use arbitration/recovery logic */ @@ -156,19 +156,19 @@ bdb_db_open( BackendDB *be ) if( rc == ALOCK_RECOVER ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: unclean shutdown detected;" + LDAP_XSTRING(bdb_db_open) ": unclean shutdown detected;" " attempting recovery.\n", 0, 0, 0 ); do_alock_recover = 1; do_recover = DB_RECOVER; } else if( rc == ALOCK_BUSY ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: database already in use\n", + LDAP_XSTRING(bdb_db_open) ": database already in use\n", 0, 0, 0 ); return -1; } else if( rc != ALOCK_CLEAN ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: alock package is unstable\n", + LDAP_XSTRING(bdb_db_open) ": alock package is unstable\n", 0, 0, 0 ); return -1; } @@ -186,7 +186,7 @@ bdb_db_open( BackendDB *be ) if( stat( path, &stat2 ) == 0 ) { if( stat2.st_mtime < stat1.st_mtime ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: DB_CONFIG for suffix %s has changed.\n" + LDAP_XSTRING(bdb_db_open) ": DB_CONFIG for suffix %s has changed.\n" "Performing database recovery to activate new settings.\n", be->be_suffix[0].bv_val, 0, 0 ); do_recover = DB_RECOVER; @@ -196,7 +196,7 @@ bdb_db_open( BackendDB *be ) } else { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: Warning - No DB_CONFIG file found " + LDAP_XSTRING(bdb_db_open) ": Warning - No DB_CONFIG file found " "in directory %s: (%d)\n" "Expect poor performance for suffix %s.\n", bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val ); @@ -208,7 +208,7 @@ bdb_db_open( BackendDB *be ) */ if ( do_recover && ( slapMode & SLAP_TOOL_READONLY )) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: Recovery skipped in read-only mode. " + LDAP_XSTRING(bdb_db_open) ": Recovery skipped in read-only mode. " "Run manual recovery if errors are encountered.\n", 0, 0, 0 ); do_recover = 0; @@ -218,7 +218,7 @@ bdb_db_open( BackendDB *be ) /* An existing environment in Quick mode has nothing to recover. */ if ( alockt && do_recover ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: cannot recover, database must be reinitialized.\n", + LDAP_XSTRING(bdb_db_open) ": cannot recover, database must be reinitialized.\n", 0, 0, 0 ); rc = -1; goto fail; @@ -227,7 +227,7 @@ bdb_db_open( BackendDB *be ) rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: db_env_create failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": db_env_create failed: %s (%d)\n", db_strerror(rc), rc, 0 ); goto fail; } @@ -244,10 +244,11 @@ bdb_db_open( BackendDB *be ) * currently requested modes, remove it. */ if ( !do_recover && ( alockt ^ quick )) { +shm_retry: rc = bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, DB_FORCE ); if ( rc ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: dbenv remove failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": dbenv remove failed: %s (%d)\n", db_strerror(rc), rc, 0 ); bdb->bi_dbenv = NULL; goto fail; @@ -255,7 +256,7 @@ bdb_db_open( BackendDB *be ) rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: db_env_create failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": db_env_create failed: %s (%d)\n", db_strerror(rc), rc, 0 ); goto fail; } @@ -274,7 +275,7 @@ bdb_db_open( BackendDB *be ) bdb->bi_dbenv_xflags, 1); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: dbenv_set_flags failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": dbenv_set_flags failed: %s (%d)\n", db_strerror(rc), rc, 0 ); goto fail; } @@ -283,7 +284,7 @@ bdb_db_open( BackendDB *be ) #define BDB_TXN_FLAGS (DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN) Debug( LDAP_DEBUG_TRACE, - "bdb_db_open: dbenv_open(%s)\n", + LDAP_XSTRING(bdb_db_open) ": dbenv_open(%s)\n", bdb->bi_dbenv_home, 0, 0); flags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD; @@ -296,12 +297,25 @@ bdb_db_open( BackendDB *be ) bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key ); flags |= DB_SYSTEM_MEM; } - rc = bdb->bi_dbenv->open( bdb->bi_dbenv, dbhome, + rc = (bdb->bi_dbenv->open)( bdb->bi_dbenv, dbhome, flags | do_recover, bdb->bi_dbenv_mode ); if ( rc ) { + /* Regular open failed, probably a missing shm environment. + * Start over, do a recovery. + */ + if ( !do_recover && bdb->bi_shm_key ) { + bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); + rc = db_env_create( &bdb->bi_dbenv, 0 ); + if( rc == 0 ) { + Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) + ": Shared memory env open failed, assuming stale env\n", + 0, 0, 0 ); + goto shm_retry; + } + } Debug( LDAP_DEBUG_ANY, - "bdb_db_open: Database cannot be %s, err %d. " + LDAP_XSTRING(bdb_db_open) ": Database cannot be %s, err %d. " "Restore from backup!\n", do_recover ? "recovered" : "opened", rc, 0); goto fail; @@ -309,7 +323,7 @@ bdb_db_open( BackendDB *be ) if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: alock_recover failed\n", + LDAP_XSTRING(bdb_db_open) ": alock_recover failed\n", 0, 0, 0 ); rc = -1; goto fail; @@ -323,6 +337,11 @@ bdb_db_open( BackendDB *be ) } #endif + /* Default dncache to 2x entrycache */ + if ( bdb->bi_cache.c_maxsize && !bdb->bi_cache.c_eimax ) { + bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize * 2; + } + if ( bdb->bi_idl_cache_max_size ) { bdb->bi_idl_tree = NULL; bdb->bi_idl_cache_size = 0; @@ -347,7 +366,7 @@ bdb_db_open( BackendDB *be ) rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: db_create(%s) failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); goto fail; } @@ -408,7 +427,7 @@ bdb_db_open( BackendDB *be ) snprintf( buf, sizeof(buf), "%s/%s", bdb->bi_dbenv_home, bdbi_databases[i].file ); Debug( LDAP_DEBUG_ANY, - "bdb_db_open: db_open(%s) failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": db_open(%s) failed: %s (%d)\n", buf, db_strerror(rc), rc ); db->bdi_db->close( db->bdi_db, 0 ); goto fail; @@ -426,15 +445,38 @@ bdb_db_open( BackendDB *be ) rc = bdb_last_id( be, NULL ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, - "bdb_db_open: last_id(%s) failed: %s (%d)\n", + LDAP_XSTRING(bdb_db_open) ": last_id(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); goto fail; } if ( !quick ) { +#if DB_VERSION_FULL >= 0x04060012 + u_int32_t lid; + XLOCK_ID(bdb->bi_dbenv, &lid); + __lock_getlocker(bdb->bi_dbenv->lk_handle, lid, 0, &bdb->bi_cache.c_locker); +#else XLOCK_ID(bdb->bi_dbenv, &bdb->bi_cache.c_locker); +#endif } + entry_prealloc( bdb->bi_cache.c_maxsize ); + attr_prealloc( bdb->bi_cache.c_maxsize * 20 ); + + /* setup for empty-DN contexts */ + if ( BER_BVISEMPTY( &be->be_nsuffix[0] )) { + rc = bdb_id2entry( be, NULL, 0, 0, &e ); + } + if ( !e ) { + e = entry_alloc(); + e->e_id = 0; + ber_dupbv( &e->e_name, (struct berval *)&slap_empty_bv ); + ber_dupbv( &e->e_nname, (struct berval *)&slap_empty_bv ); + } + e->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END; + e->e_private = &bdb->bi_cache.c_dntree; + bdb->bi_cache.c_dntree.bei_e = e; + /* monitor setup */ rc = bdb_monitor_db_open( be ); if ( rc != 0 ) { @@ -443,17 +485,15 @@ bdb_db_open( BackendDB *be ) bdb->bi_flags |= BDB_IS_OPEN; - entry_prealloc( bdb->bi_cache.c_maxsize ); - attr_prealloc( bdb->bi_cache.c_maxsize * 20 ); return 0; fail: - bdb_db_close( be ); + bdb_db_close( be, NULL ); return rc; } static int -bdb_db_close( BackendDB *be ) +bdb_db_close( BackendDB *be, ConfigReply *cr ) { int rc; struct bdb_info *bdb = (struct bdb_info *) be->be_private; @@ -463,6 +503,15 @@ bdb_db_close( BackendDB *be ) /* monitor handling */ (void)bdb_monitor_db_close( be ); + { + Entry *e = bdb->bi_cache.c_dntree.bei_e; + if ( e ) { + bdb->bi_cache.c_dntree.bei_e = NULL; + e->e_private = NULL; + bdb_entry_return( e ); + } + } + bdb->bi_flags &= ~BDB_IS_OPEN; ber_bvarray_free( bdb->bi_db_config ); @@ -500,7 +549,11 @@ bdb_db_close( BackendDB *be ) if( bdb->bi_dbenv ) { /* Free cache locker if we enabled locking */ if ( !( slapMode & SLAP_TOOL_QUICK )) { +#if DB_VERSION_FULL >= 0x04060012 + XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker->id); +#else XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker); +#endif bdb->bi_cache.c_locker = 0; } #ifdef BDB_REUSE_LOCKERS @@ -539,7 +592,7 @@ bdb_db_close( BackendDB *be ) } static int -bdb_db_destroy( BackendDB *be ) +bdb_db_destroy( BackendDB *be, ConfigReply *cr ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; @@ -564,16 +617,6 @@ bdb_db_destroy( BackendDB *be ) ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock ); ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock ); - { - Entry *e; - e = bdb->bi_cache.c_dntree.bei_e; - bdb->bi_cache.c_dntree.bei_e = NULL; - e->e_private = NULL; - BER_BVZERO( &e->e_name ); - BER_BVZERO( &e->e_nname ); - entry_free( e ); - } - ch_free( bdb ); be->be_private = NULL; @@ -695,7 +738,6 @@ bdb_back_initialize( bi->bi_tool_entry_reindex = bdb_tool_entry_reindex; bi->bi_tool_sync = 0; bi->bi_tool_dn2id_get = bdb_tool_dn2id_get; - bi->bi_tool_id2entry_get = bdb_tool_id2entry_get; bi->bi_tool_entry_modify = bdb_tool_entry_modify; bi->bi_connection_init = 0; diff --git a/servers/slapd/back-bdb/key.c b/servers/slapd/back-bdb/key.c index 7128a6c5db..161caf7011 100644 --- a/servers/slapd/back-bdb/key.c +++ b/servers/slapd/back-bdb/key.c @@ -30,7 +30,7 @@ int bdb_key_read( Backend *be, DB *db, - u_int32_t locker, + BDB_LOCKER locker, struct berval *k, ID *ids, DBC **saved_cursor, diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index 408ad24f6a..df1cf3dfca 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -281,7 +281,7 @@ bdb_modify( Operation *op, SlapReply *rs ) Entry dummy = {0}; int fakeroot = 0; - u_int32_t locker = 0; + BDB_LOCKER locker = 0; DB_LOCK lock; int num_retries = 0; @@ -522,7 +522,7 @@ retry: /* transaction retry */ } /* Modify the entry */ dummy = *e; - rs->sr_err = bdb_modify_internal( op, lt2, op->oq_modify.rs_modlist, + rs->sr_err = bdb_modify_internal( op, lt2, op->orm_modlist, &dummy, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { @@ -588,6 +588,8 @@ retry: /* transaction retry */ } else { rs->sr_err = LDAP_X_NO_OPERATION; ltid = NULL; + /* Only free attrs if they were dup'd. */ + if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; goto return_results; } } else { diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index 1497a19822..bb6dea16f3 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -46,7 +46,7 @@ bdb_modrdn( Operation *op, SlapReply *rs ) int manageDSAit = get_manageDSAit( op ); - u_int32_t locker = 0; + BDB_LOCKER locker = 0; DB_LOCK lock, plock, nplock; int num_retries = 0; @@ -542,6 +542,8 @@ retry: /* transaction retry */ struct berval bv = {0, NULL}; dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx ); ber_dupbv( &new_ndn, &bv ); + /* FIXME: why not call dnNormalize() w/o ctx? */ + op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": new ndn=%s\n", diff --git a/servers/slapd/back-bdb/monitor.c b/servers/slapd/back-bdb/monitor.c index 9114fac70b..ffde364a27 100644 --- a/servers/slapd/back-bdb/monitor.c +++ b/servers/slapd/back-bdb/monitor.c @@ -32,9 +32,18 @@ static ObjectClass *oc_olmBDBDatabase; static AttributeDescription *ad_olmBDBEntryCache, - *ad_olmBDBEntryInfo, *ad_olmBDBIDLCache, + *ad_olmBDBDNCache, *ad_olmBDBIDLCache, *ad_olmDbDirectory; +#ifdef BDB_MONITOR_IDX +static int +bdb_monitor_idx_entry_add( + struct bdb_info *bdb, + Entry *e ); + +static AttributeDescription *ad_olmBDBNotIndexed; +#endif /* BDB_MONITOR_IDX */ + /* * NOTE: there's some confusion in monitor OID arc; * by now, let's consider: @@ -71,12 +80,12 @@ static struct { &ad_olmBDBEntryCache }, { "( olmBDBAttributes:2 " - "NAME ( 'olmBDBEntryInfo' ) " - "DESC 'Number of items in EntryInfo Cache' " + "NAME ( 'olmBDBDNCache' ) " + "DESC 'Number of items in DN Cache' " "SUP monitorCounter " "NO-USER-MODIFICATION " "USAGE dSAOperation )", - &ad_olmBDBEntryInfo }, + &ad_olmBDBDNCache }, { "( olmBDBAttributes:3 " "NAME ( 'olmBDBIDLCache' ) " @@ -95,6 +104,16 @@ static struct { "USAGE dSAOperation )", &ad_olmDbDirectory }, +#ifdef BDB_MONITOR_IDX + { "( olmBDBAttributes:5 " + "NAME ( 'olmBDBNotIndexed' ) " + "DESC 'Missing indexes resulting from candidate selection' " + "SUP monitoredInfo " + "NO-USER-MODIFICATION " + "USAGE dSAOperation )", + &ad_olmBDBNotIndexed }, +#endif /* BDB_MONITOR_IDX */ + { NULL } }; @@ -109,9 +128,12 @@ static struct { "SUP top AUXILIARY " "MAY ( " "olmBDBEntryCache " - "$ olmBDBEntryInfo " + "$ olmBDBDNCache " "$ olmBDBIDLCache " "$ olmDbDirectory " +#ifdef BDB_MONITOR_IDX + "$ olmBDBNotIndexed " +#endif /* BDB_MONITOR_IDX */ ") )", &oc_olmBDBDatabase }, @@ -139,7 +161,7 @@ bdb_monitor_update( bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_cursize ); ber_bvreplace( &a->a_vals[ 0 ], &bv ); - a = attr_find( e->e_attrs, ad_olmBDBEntryInfo ); + a = attr_find( e->e_attrs, ad_olmBDBDNCache ); assert( a != NULL ); bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_eiused ); ber_bvreplace( &a->a_vals[ 0 ], &bv ); @@ -149,6 +171,10 @@ bdb_monitor_update( bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_idl_cache_size ); ber_bvreplace( &a->a_vals[ 0 ], &bv ); +#ifdef BDB_MONITOR_IDX + bdb_monitor_idx_entry_add( bdb, e ); +#endif /* BDB_MONITOR_IDX */ + return SLAP_CB_CONTINUE; } @@ -275,11 +301,20 @@ bdb_monitor_db_init( BackendDB *be ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; + if ( SLAP_GLUE_SUBORDINATE( be ) ) { + return 0; + } + if ( bdb_monitor_initialize() == LDAP_SUCCESS ) { /* monitoring in back-bdb is on by default */ SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; } +#ifdef BDB_MONITOR_IDX + bdb->bi_idx = NULL; + ldap_pvt_thread_mutex_init( &bdb->bi_idx_mutex ); +#endif /* BDB_MONITOR_IDX */ + bdb->bi_monitor.bdm_scope = -1; return 0; @@ -304,6 +339,10 @@ bdb_monitor_db_open( BackendDB *be ) return 0; } + if ( SLAP_GLUE_SUBORDINATE( be ) ) { + return 0; + } + mi = backend_info( "monitor" ); if ( !mi || !mi->bi_extra ) { SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; @@ -386,7 +425,7 @@ bdb_monitor_db_open( BackendDB *be ) next->a_nvals = next->a_vals; next = next->a_next; - next->a_desc = ad_olmBDBEntryInfo; + next->a_desc = ad_olmBDBDNCache; value_add_one( &next->a_vals, &bv ); next->a_nvals = next->a_vals; next = next->a_next; @@ -455,8 +494,12 @@ bdb_monitor_db_open( BackendDB *be ) cb->mc_free = bdb_monitor_free; cb->mc_private = (void *)bdb; - rc = mbe->register_entry_attrs( NULL, a, cb, - base, bdb->bi_monitor.bdm_scope, filter ); + /* make sure the database is registered; then add monitor attributes */ + rc = mbe->register_database( be ); + if ( rc == 0 ) { + rc = mbe->register_entry_attrs( NULL, a, cb, + base, bdb->bi_monitor.bdm_scope, filter ); + } cleanup:; if ( rc != 0 ) { @@ -496,6 +539,10 @@ bdb_monitor_db_close( BackendDB *be ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; + if ( SLAP_GLUE_SUBORDINATE( be ) ) { + return 0; + } + if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_filter ) ) { BackendInfo *mi = backend_info( "monitor" ); monitor_extra_t *mbe; @@ -525,5 +572,217 @@ bdb_monitor_db_close( BackendDB *be ) int bdb_monitor_db_destroy( BackendDB *be ) { + if ( SLAP_GLUE_SUBORDINATE( be ) ) { + return 0; + } + +#ifdef BDB_MONITOR_IDX + { + struct bdb_info *bdb = (struct bdb_info *) be->be_private; + + /* TODO: free tree */ + ldap_pvt_thread_mutex_destroy( &bdb->bi_idx_mutex ); + avl_free( bdb->bi_idx, ch_free ); + } +#endif /* BDB_MONITOR_IDX */ + return 0; } + +#ifdef BDB_MONITOR_IDX + +#define BDB_MONITOR_IDX_TYPES (4) + +typedef struct monitor_idx_t monitor_idx_t; + +struct monitor_idx_t { + AttributeDescription *idx_ad; + unsigned long idx_count[BDB_MONITOR_IDX_TYPES]; +}; + +static int +bdb_monitor_bitmask2key( slap_mask_t bitmask ) +{ + int key; + + for ( key = 0; key < 8*sizeof(slap_mask_t) && !( bitmask & 0x1U ); key++ ) { + bitmask >>= 1; + } + + return key; +} + +static struct berval idxbv[] = { + BER_BVC( "present=" ), + BER_BVC( "equality=" ), + BER_BVC( "approx=" ), + BER_BVC( "substr=" ), + BER_BVNULL +}; + +static ber_len_t +bdb_monitor_idx2len( monitor_idx_t *idx ) +{ + int i; + ber_len_t len = 0; + + for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { + if ( idx->idx_count[ i ] != 0 ) { + len += idxbv[i].bv_len; + } + } + + return len; +} + +static int +monitor_idx_cmp( const void *p1, const void *p2 ) +{ + const monitor_idx_t *idx1 = (const monitor_idx_t *)p1; + const monitor_idx_t *idx2 = (const monitor_idx_t *)p2; + + return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ); +} + +static int +monitor_idx_dup( void *p1, void *p2 ) +{ + monitor_idx_t *idx1 = (monitor_idx_t *)p1; + monitor_idx_t *idx2 = (monitor_idx_t *)p2; + + return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0; +} + +int +bdb_monitor_idx_add( + struct bdb_info *bdb, + AttributeDescription *desc, + slap_mask_t type ) +{ + monitor_idx_t idx_dummy = { 0 }, + *idx; + int rc = 0, key; + + idx_dummy.idx_ad = desc; + key = bdb_monitor_bitmask2key( type ) - 1; + if ( key >= BDB_MONITOR_IDX_TYPES ) { + /* invalid index type */ + return -1; + } + + ldap_pvt_thread_mutex_lock( &bdb->bi_idx_mutex ); + + idx = (monitor_idx_t *)avl_find( bdb->bi_idx, + (caddr_t)&idx_dummy, monitor_idx_cmp ); + if ( idx == NULL ) { + idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 ); + idx->idx_ad = desc; + idx->idx_count[ key ] = 1; + + switch ( avl_insert( &bdb->bi_idx, (caddr_t)idx, + monitor_idx_cmp, monitor_idx_dup ) ) + { + case 0: + break; + + default: + ch_free( idx ); + rc = -1; + } + + } else { + idx->idx_count[ key ]++; + } + + ldap_pvt_thread_mutex_unlock( &bdb->bi_idx_mutex ); + + return rc; +} + +static int +bdb_monitor_idx_apply( void *v_idx, void *v_valp ) +{ + monitor_idx_t *idx = (monitor_idx_t *)v_idx; + BerVarray *valp = (BerVarray *)v_valp; + + struct berval bv; + char *ptr; + char count_buf[ BDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ]; + ber_len_t count_len[ BDB_MONITOR_IDX_TYPES ], + idx_len; + int i, num = 0; + + idx_len = bdb_monitor_idx2len( idx ); + + bv.bv_len = 0; + for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { + if ( idx->idx_count[ i ] == 0 ) { + continue; + } + + count_len[ i ] = snprintf( count_buf[ i ], + sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] ); + bv.bv_len += count_len[ i ]; + num++; + } + + bv.bv_len += idx->idx_ad->ad_cname.bv_len + + num + + idx_len; + ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); + ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val ); + for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { + if ( idx->idx_count[ i ] == 0 ) { + continue; + } + + ptr[ 0 ] = '#'; + ++ptr; + ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val ); + ptr = lutil_strcopy( ptr, count_buf[ i ] ); + } + + ber_bvarray_add( valp, &bv ); + + return 0; +} + +static int +bdb_monitor_idx_entry_add( + struct bdb_info *bdb, + Entry *e ) +{ + BerVarray vals = NULL; + Attribute *a; + + a = attr_find( e->e_attrs, ad_olmBDBNotIndexed ); + + ldap_pvt_thread_mutex_lock( &bdb->bi_idx_mutex ); + + avl_apply( bdb->bi_idx, bdb_monitor_idx_apply, + &vals, -1, AVL_INORDER ); + + ldap_pvt_thread_mutex_unlock( &bdb->bi_idx_mutex ); + + if ( vals != NULL ) { + if ( a != NULL ) { + assert( a->a_nvals == a->a_vals ); + + ber_bvarray_free( a->a_vals ); + + } else { + Attribute **ap; + + for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) + ; + *ap = attr_alloc( ad_olmBDBNotIndexed ); + a = *ap; + } + a->a_vals = vals; + a->a_nvals = a->a_vals; + } + + return 0; +} + +#endif /* BDB_MONITOR_IDX */ diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 77aaf6c688..b69325f2aa 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -84,7 +84,7 @@ bdb_db_cache( int bdb_dn2entry LDAP_P(( Operation *op, DB_TXN *tid, struct berval *dn, EntryInfo **e, int matched, - u_int32_t locker, DB_LOCK *lock )); + BDB_LOCKER locker, DB_LOCK *lock )); /* * dn2id.c @@ -120,7 +120,7 @@ int bdb_dn2id_children( int bdb_dn2idl( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, struct berval *ndn, EntryInfo *ei, ID *ids, @@ -133,7 +133,7 @@ int bdb_dn2idl( int bdb_dn2id_parent( Operation *op, DB_TXN *txn, - u_int32_t locker, + BDB_LOCKER locker, EntryInfo *ei, ID *idp ); @@ -168,7 +168,7 @@ char *ebcdic_dberror( int rc ); int bdb_filter_candidates( Operation *op, - u_int32_t locker, + BDB_LOCKER locker, Filter *f, ID *ids, ID *tmp, @@ -202,7 +202,7 @@ int bdb_id2entry_delete( int bdb_id2entry( BackendDB *be, DB_TXN *tid, - u_int32_t locker, + BDB_LOCKER locker, ID id, Entry **e); #endif @@ -285,7 +285,7 @@ unsigned bdb_idl_search( ID *ids, ID id ); int bdb_idl_fetch_key( BackendDB *be, DB *db, - u_int32_t locker, + BDB_LOCKER locker, DBT *key, ID *ids, DBC **saved_cursor, @@ -391,7 +391,7 @@ extern int bdb_key_read( Backend *be, DB *db, - u_int32_t locker, + BDB_LOCKER locker, struct berval *k, ID *ids, DBC **saved_cursor, @@ -443,6 +443,15 @@ int bdb_monitor_db_open( BackendDB *be ); int bdb_monitor_db_close( BackendDB *be ); int bdb_monitor_db_destroy( BackendDB *be ); +#ifdef BDB_MONITOR_IDX +#define bdb_monitor_idx_add BDB_SYMBOL(monitor_idx_add) +int +bdb_monitor_idx_add( + struct bdb_info *bdb, + AttributeDescription *desc, + slap_mask_t type ); +#endif /* BDB_MONITOR_IDX */ + /* * cache.c */ @@ -504,7 +513,7 @@ int bdb_cache_add( EntryInfo *pei, Entry *e, struct berval *nrdn, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ); int bdb_cache_modrdn( @@ -513,14 +522,14 @@ int bdb_cache_modrdn( struct berval *nrdn, Entry *new, EntryInfo *ein, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ); int bdb_cache_modify( struct bdb_info *bdb, Entry *e, Attribute *newAttrs, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ); int bdb_cache_find_ndn( @@ -539,21 +548,21 @@ int bdb_cache_find_id( ID id, EntryInfo **eip, int islocked, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ); int bdb_cache_find_parent( Operation *op, DB_TXN *txn, - u_int32_t locker, + BDB_LOCKER locker, ID id, EntryInfo **res ); int bdb_cache_delete( struct bdb_info *bdb, Entry *e, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock ); void bdb_cache_delete_cleanup( @@ -573,7 +582,7 @@ int hdb_cache_load( #define bdb_cache_entry_db_relock BDB_SYMBOL(cache_entry_db_relock) int bdb_cache_entry_db_relock( struct bdb_info *bdb, - u_int32_t locker, + BDB_LOCKER locker, EntryInfo *ei, int rw, int tryOnly, @@ -587,7 +596,7 @@ int bdb_cache_entry_db_unlock( #define bdb_locker_id BDB_SYMBOL(locker_id) #define bdb_locker_flush BDB_SYMBOL(locker_flush) -int bdb_locker_id( Operation *op, DB_ENV *env, u_int32_t *locker ); +int bdb_locker_id( Operation *op, DB_ENV *env, BDB_LOCKER *locker ); void bdb_locker_flush( DB_ENV *env ); #define LOCK_ID_FREE(env, locker) ((void)0) @@ -632,7 +641,6 @@ bdb_trans_backoff( int num_retries ); #define bdb_tool_entry_put BDB_SYMBOL(tool_entry_put) #define bdb_tool_entry_reindex BDB_SYMBOL(tool_entry_reindex) #define bdb_tool_dn2id_get BDB_SYMBOL(tool_dn2id_get) -#define bdb_tool_id2entry_get BDB_SYMBOL(tool_id2entry_get) #define bdb_tool_entry_modify BDB_SYMBOL(tool_entry_modify) #define bdb_tool_idl_add BDB_SYMBOL(tool_idl_add) @@ -663,7 +671,6 @@ extern BI_tool_entry_get bdb_tool_entry_get; extern BI_tool_entry_put bdb_tool_entry_put; extern BI_tool_entry_reindex bdb_tool_entry_reindex; extern BI_tool_dn2id_get bdb_tool_dn2id_get; -extern BI_tool_id2entry_get bdb_tool_id2entry_get; extern BI_tool_entry_modify bdb_tool_entry_modify; int bdb_tool_idl_add( BackendDB *be, DB *db, DB_TXN *txn, DBT *key, ID id ); diff --git a/servers/slapd/back-bdb/referral.c b/servers/slapd/back-bdb/referral.c index d31056eebb..29b3831e72 100644 --- a/servers/slapd/back-bdb/referral.c +++ b/servers/slapd/back-bdb/referral.c @@ -28,7 +28,7 @@ bdb_referrals( Operation *op, SlapReply *rs ) EntryInfo *ei; int rc = LDAP_SUCCESS; - u_int32_t locker; + BDB_LOCKER locker; DB_LOCK lock; if( op->o_tag == LDAP_REQ_SEARCH ) { @@ -87,8 +87,8 @@ dn2entry_retry: if ( e != NULL ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_referrals) - ": op=%ld target=\"%s\" matched=\"%s\"\n", - (long) op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val ); + ": tag=%lu target=\"%s\" matched=\"%s\"\n", + (unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val ); if( is_entry_referral( e ) ) { BerVarray ref = get_entry_referrals( op, e ); @@ -138,8 +138,8 @@ dn2entry_retry: Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_referrals) - ": op=%ld target=\"%s\" matched=\"%s\"\n", - (long) op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val ); + ": tag=%lu target=\"%s\" matched=\"%s\"\n", + (unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val ); rs->sr_matched = e->e_name.bv_val; if( rs->sr_ref != NULL ) { diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 94dd7c87ae..5f0f583c69 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -31,7 +31,7 @@ static int search_candidates( Operation *op, SlapReply *rs, Entry *e, - u_int32_t locker, + BDB_LOCKER locker, ID *ids, ID *scopes ); @@ -51,7 +51,7 @@ static Entry * deref_base ( SlapReply *rs, Entry *e, Entry **matched, - u_int32_t locker, + BDB_LOCKER locker, DB_LOCK *lock, ID *tmp, ID *visited ) @@ -143,7 +143,7 @@ static int search_aliases( Operation *op, SlapReply *rs, Entry *e, - u_int32_t locker, + BDB_LOCKER locker, ID *ids, ID *scopes, ID *stack ) @@ -321,7 +321,7 @@ bdb_search( Operation *op, SlapReply *rs ) ID lastid = NOID; AttributeName *attrs; - u_int32_t locker = 0; + BDB_LOCKER locker = 0; DB_LOCK lock; struct bdb_op_info *opinfo = NULL; DB_TXN *ltid = NULL; @@ -660,6 +660,15 @@ loop_begin: goto done; } + /* mostly needed by internal searches, + * e.g. related to syncrepl, for whom + * abandon does not get set... */ + if ( slapd_shutdown ) { + rs->sr_err = LDAP_UNAVAILABLE; + send_ldap_disconnect( op, rs ); + goto done; + } + /* check time limit */ if ( op->ors_tlimit != SLAP_NO_LIMIT && slap_get_time() > stoptime ) @@ -1011,7 +1020,7 @@ static int search_candidates( Operation *op, SlapReply *rs, Entry *e, - u_int32_t locker, + BDB_LOCKER locker, ID *ids, ID *scopes ) { diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c index f22a057ec9..f8cf1e138d 100644 --- a/servers/slapd/back-bdb/tools.c +++ b/servers/slapd/back-bdb/tools.c @@ -27,7 +27,8 @@ static DBC *cursor = NULL; static DBT key, data; static EntryHeader eh; -static int eoff; +static ID nid, previd = NOID; +static char ehbuf[16]; typedef struct dn_id { ID id; @@ -74,7 +75,11 @@ static ldap_pvt_thread_mutex_t bdb_tool_index_mutex; static ldap_pvt_thread_cond_t bdb_tool_index_cond_main; static ldap_pvt_thread_cond_t bdb_tool_index_cond_work; +static ldap_pvt_thread_mutex_t bdb_tool_trickle_mutex; +static ldap_pvt_thread_cond_t bdb_tool_trickle_cond; + static void * bdb_tool_index_task( void *ctx, void *ptr ); +static void * bdb_tool_trickle_task( void *ctx, void *ptr ); int bdb_tool_entry_open( BackendDB *be, int mode ) @@ -84,7 +89,9 @@ int bdb_tool_entry_open( /* initialize key and data thangs */ DBTzero( &key ); DBTzero( &data ); - key.flags = DB_DBT_REALLOC; + key.flags = DB_DBT_USERMEM; + key.data = &nid; + key.size = key.ulen = sizeof( nid ); data.flags = DB_DBT_USERMEM; if (cursor == NULL) { @@ -97,24 +104,29 @@ int bdb_tool_entry_open( } /* Set up for threaded slapindex */ - if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK - && bdb->bi_nattrs ) { + if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) { if ( !bdb_tool_info ) { - int i; + ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex ); + ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond ); + ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_trickle_task, bdb->bi_dbenv ); + ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex ); ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main ); ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work ); - bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int )); - bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec )); - bdb_tool_index_tcount = slap_tool_thread_max - 1; - for (i=1; ibi_nattrs ) { + int i; + bdb_tool_index_threads = ch_malloc( slap_tool_thread_max * sizeof( int )); + bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec )); + bdb_tool_index_tcount = slap_tool_thread_max - 1; + for (i=1; ibe_private; - char buf[16], *dptr; assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); assert( bdb != NULL ); - + /* Get the header */ - data.ulen = data.dlen = sizeof( buf ); - data.data = buf; + data.ulen = data.dlen = sizeof( ehbuf ); + data.data = ehbuf; data.flags |= DB_DBT_PARTIAL; rc = cursor->c_get( cursor, &key, &data, DB_NEXT ); @@ -198,17 +208,8 @@ ID bdb_tool_entry_next( } } - dptr = eh.bv.bv_val; - eh.bv.bv_val = buf; - eh.bv.bv_len = data.size; - rc = entry_header( &eh ); - eoff = eh.data - eh.bv.bv_val; - eh.bv.bv_val = dptr; - if( rc ) { - return NOID; - } - BDB_DISK2ID( key.data, &id ); + previd = id; return id; } @@ -238,41 +239,39 @@ ID bdb_tool_dn2id_get( return ei->bei_id; } -int bdb_tool_id2entry_get( - Backend *be, - ID id, - Entry **e -) -{ - int rc = bdb_id2entry( be, NULL, 0, id, e ); - - if ( rc == DB_NOTFOUND && id == 0 ) { - Entry *dummy = ch_calloc( 1, sizeof(Entry) ); - struct berval gluebv = BER_BVC("glue"); - dummy->e_name.bv_val = ch_strdup( "" ); - dummy->e_nname.bv_val = ch_strdup( "" ); - attr_merge_one( dummy, slap_schema.si_ad_objectClass, &gluebv, NULL ); - attr_merge_one( dummy, slap_schema.si_ad_structuralObjectClass, - &gluebv, NULL ); - *e = dummy; - rc = LDAP_SUCCESS; - } - return rc; -} - Entry* bdb_tool_entry_get( BackendDB *be, ID id ) { - int rc; Entry *e = NULL; + char *dptr; + int rc, eoff; assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); + if ( id != previd ) { + data.ulen = data.dlen = sizeof( ehbuf ); + data.data = ehbuf; + data.flags |= DB_DBT_PARTIAL; + + BDB_ID2DISK( id, &nid ); + rc = cursor->c_get( cursor, &key, &data, DB_SET ); + if ( rc ) goto done; + } + + /* Get the header */ + dptr = eh.bv.bv_val; + eh.bv.bv_val = ehbuf; + eh.bv.bv_len = data.size; + rc = entry_header( &eh ); + eoff = eh.data - eh.bv.bv_val; + eh.bv.bv_val = dptr; + if ( rc ) goto done; + /* Get the size */ - data.flags ^= DB_DBT_PARTIAL; + data.flags &= ~DB_DBT_PARTIAL; data.ulen = 0; rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); - if ( rc != DB_BUFFER_SMALL ) goto leave; + if ( rc != DB_BUFFER_SMALL ) goto done; /* Allocate a block and retrieve the data */ eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size; @@ -285,7 +284,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) eh.data += eoff; rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); - if ( rc ) goto leave; + if ( rc ) goto done; #ifdef SLAP_ZONE_ALLOC /* FIXME: will add ctx later */ @@ -307,7 +306,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) op.o_tmpmemctx = NULL; op.o_tmpmfuncs = &ch_mfuncs; - rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei ); + rc = bdb_cache_find_parent( &op, NULL, CURSOR_GETLOCKER(cursor), id, &ei ); if ( rc == LDAP_SUCCESS ) { bdb_cache_entryinfo_unlock( ei ); e->e_private = ei; @@ -319,7 +318,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id ) } #endif } -leave: +done: return e; } @@ -522,6 +521,12 @@ ID bdb_tool_entry_put( goto done; } + if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) { + ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex ); + ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond ); + ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex ); + } + if ( !bdb->bi_linear_index ) rc = bdb_tool_index_add( &op, tid, e ); if( rc != 0 ) { @@ -1087,6 +1092,25 @@ int bdb_tool_idl_add( } #endif +static void * +bdb_tool_trickle_task( void *ctx, void *ptr ) +{ + DB_ENV *env = ptr; + int wrote; + + ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex ); + while ( 1 ) { + ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond, + &bdb_tool_trickle_mutex ); + if ( slapd_shutdown ) + break; + env->memp_trickle( env, 30, &wrote ); + } + ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex ); + + return NULL; +} + static void * bdb_tool_index_task( void *ctx, void *ptr ) { diff --git a/servers/slapd/back-dnssrv/bind.c b/servers/slapd/back-dnssrv/bind.c index 20fd959fc5..6bf68fda5d 100644 --- a/servers/slapd/back-dnssrv/bind.c +++ b/servers/slapd/back-dnssrv/bind.c @@ -32,30 +32,42 @@ int dnssrv_back_bind( - Operation *op, - SlapReply *rs ) + Operation *op, + SlapReply *rs ) { - Debug( LDAP_DEBUG_TRACE, "DNSSRV: bind %s (%d)\n", - op->o_req_dn.bv_val == NULL ? "" : op->o_req_dn.bv_val, - op->oq_bind.rb_method, NULL ); - - if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE && - !BER_BVISNULL( &op->oq_bind.rb_cred ) && - !BER_BVISEMPTY( &op->oq_bind.rb_cred ) ) + Debug( LDAP_DEBUG_TRACE, "DNSSRV: bind dn=\"%s\" (%d)\n", + BER_BVISNULL( &op->o_req_dn ) ? "" : op->o_req_dn.bv_val, + op->orb_method, 0 ); + + /* allow rootdn as a means to auth without the need to actually + * contact the proxied DSA */ + switch ( be_rootdn_bind( op, NULL ) ) { + case LDAP_SUCCESS: + /* frontend will send result */ + return rs->sr_err; + + default: + /* treat failure and like any other bind, otherwise + * it could reveal the DN of the rootdn */ + break; + } + + if ( !BER_BVISNULL( &op->orb_cred ) && + !BER_BVISEMPTY( &op->orb_cred ) ) { + /* simple bind */ Statslog( LDAP_DEBUG_STATS, - "%s DNSSRV BIND dn=\"%s\" provided passwd\n", + "%s DNSSRV BIND dn=\"%s\" provided cleartext passwd\n", op->o_log_prefix, BER_BVISNULL( &op->o_req_dn ) ? "" : op->o_req_dn.bv_val , 0, 0, 0 ); - Debug( LDAP_DEBUG_TRACE, - "DNSSRV: BIND dn=\"%s\" provided cleartext password\n", - BER_BVISNULL( &op->o_req_dn ) ? "" : op->o_req_dn.bv_val, 0, 0 ); - send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "you shouldn't send strangers your password" ); } else { + /* unauthenticated bind */ + /* NOTE: we're not going to get here anyway: + * unauthenticated bind is dealt with by the frontend */ Debug( LDAP_DEBUG_TRACE, "DNSSRV: BIND dn=\"%s\"\n", BER_BVISNULL( &op->o_req_dn ) ? "" : op->o_req_dn.bv_val, 0, 0 ); diff --git a/servers/slapd/back-dnssrv/init.c b/servers/slapd/back-dnssrv/init.c index 365e47dfdb..0e5baca33b 100644 --- a/servers/slapd/back-dnssrv/init.c +++ b/servers/slapd/back-dnssrv/init.c @@ -24,8 +24,11 @@ #include #include +#include +#include #include "slap.h" +#include "config.h" #include "proto-dnssrv.h" int @@ -89,14 +92,16 @@ dnssrv_back_open( int dnssrv_back_db_init( - Backend *be ) + Backend *be, + ConfigReply *cr) { return 0; } int dnssrv_back_db_destroy( - Backend *be ) + Backend *be, + ConfigReply *cr ) { return 0; } diff --git a/servers/slapd/back-ldap/add.c b/servers/slapd/back-ldap/add.c index 9a5c4f5422..8398162ee4 100644 --- a/servers/slapd/back-ldap/add.c +++ b/servers/slapd/back-ldap/add.c @@ -93,8 +93,7 @@ ldap_back_add( retry: ctrls = op->o_ctrls; - rs->sr_err = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rs->sr_err = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -109,13 +108,13 @@ retry: retrying &= ~LDAP_BACK_RETRYING; if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup: - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( attrs ) { for ( --i; i >= 0; --i ) { diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 442869861d..374a959c74 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -310,6 +310,11 @@ typedef struct ldapinfo_t { #define LDAP_BACK_F_QUARANTINE (0x00010000U) +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +#define LDAP_BACK_F_ST_REQUEST (0x00020000U) +#define LDAP_BACK_F_ST_RESPONSE (0x00040000U) +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + #define LDAP_BACK_ISSET_F(ff,f) ( ( (ff) & (f) ) == (f) ) #define LDAP_BACK_ISMASK_F(ff,m,f) ( ( (ff) & (m) ) == (f) ) @@ -343,6 +348,11 @@ typedef struct ldapinfo_t { #define LDAP_BACK_QUARANTINE(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_QUARANTINE ) +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +#define LDAP_BACK_ST_REQUEST(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_ST_REQUEST) +#define LDAP_BACK_ST_RESPONSE(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_ST_RESPONSE) +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + int li_version; /* cached connections; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 2247405128..e5878a2cbd 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -173,10 +173,23 @@ ldap_back_bind( Operation *op, SlapReply *rs ) ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; ldapconn_t *lc; - int rc = 0; + LDAPControl **ctrls = NULL; + struct berval save_o_dn; + int save_o_do_not_cache, + rc = 0; ber_int_t msgid; ldap_back_send_t retrying = LDAP_BACK_RETRYING; + /* allow rootdn as a means to auth without the need to actually + * contact the proxied DSA */ + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + return rs->sr_err; + } + lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL ); if ( !lc ) { return rs->sr_err; @@ -195,11 +208,27 @@ ldap_back_bind( Operation *op, SlapReply *rs ) } LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); + /* don't add proxyAuthz; set the bindDN */ + save_o_dn = op->o_dn; + save_o_do_not_cache = op->o_do_not_cache; + op->o_dn = op->o_req_dn; + op->o_do_not_cache = 1; + + ctrls = op->o_ctrls; + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); + op->o_dn = save_o_dn; + op->o_do_not_cache = save_o_do_not_cache; + if ( rc != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + ldap_back_release_conn( li, lc ); + return( rc ); + } + retry:; /* method is always LDAP_AUTH_SIMPLE if we got here */ rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val, LDAP_SASL_SIMPLE, - &op->orb_cred, op->o_ctrls, NULL, &msgid ); + &op->orb_cred, ctrls, NULL, &msgid ); /* FIXME: should we always retry, or only when piping the bind * in the "override" connection pool? */ rc = ldap_back_op_result( lc, op, rs, msgid, @@ -212,6 +241,8 @@ retry:; } } + ldap_back_controls_free( op, rs, &ctrls ); + if ( rc == LDAP_SUCCESS ) { /* If defined, proxyAuthz will be used also when * back-ldap is the authorizing backend; for this @@ -781,13 +812,13 @@ ldap_back_getconn( op->o_ndn = op->o_req_ndn; } isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred ); - if ( isproxyauthz == -1 ) { - return NULL; - } if ( op->o_tag == LDAP_REQ_BIND ) { op->o_dn = save_o_dn; op->o_ndn = save_o_ndn; } + if ( isproxyauthz == -1 ) { + return NULL; + } lc_curr.lc_local_ndn = op->o_ndn; /* Explicit binds must not be shared; @@ -1189,6 +1220,17 @@ done:; ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex ); } +static int +ldap_back_dobind_cb( + Operation *op, + SlapReply *rs +) +{ + ber_tag_t *tptr = op->o_callback->sc_private; + op->o_tag = *tptr; + return SLAP_CB_CONTINUE; +} + /* * ldap_back_dobind_int * @@ -1213,6 +1255,8 @@ ldap_back_dobind_int( isbound, binding = 0; ber_int_t msgid; + ber_tag_t o_tag = op->o_tag; + slap_callback cb = {0}; assert( lcp != NULL ); assert( retries >= 0 ); @@ -1284,10 +1328,16 @@ retry_lock:; * then bind as the asserting identity and explicitly * add the proxyAuthz control to every operation with the * dn bound to the connection as control value. - * This is done also if this is the authrizing backend, + * This is done also if this is the authorizing backend, * but the "override" flag is given to idassert. * It allows to use SASL bind and yet proxyAuthz users */ + op->o_tag = LDAP_REQ_BIND; + cb.sc_next = op->o_callback; + cb.sc_private = &o_tag; + cb.sc_response = ldap_back_dobind_cb; + op->o_callback = &cb; + if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) { if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) { /* if we got here, it shouldn't return result */ @@ -1323,6 +1373,14 @@ retry_lock:; li->li_acl_authcID.bv_val, li->li_acl_passwd.bv_val, NULL ); + if ( defaults == NULL ) { + rs->sr_err = LDAP_OTHER; + LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + goto done; + } rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, li->li_acl_authcDN.bv_val, @@ -1401,11 +1459,15 @@ retry:; if ( rs->sr_err != LDAP_SUCCESS && ( sendok & LDAP_BACK_SENDERR ) ) { + if ( op->o_callback == &cb ) + op->o_callback = cb.sc_next; + op->o_tag = o_tag; rs->sr_text = "Internal proxy bind failure"; send_ldap_result( op, rs ); } - return 0; + rc = 0; + goto leave; } rc = ldap_back_op_result( lc, op, rs, msgid, @@ -1424,6 +1486,11 @@ done:; ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); } +leave:; + if ( op->o_callback == &cb ) + op->o_callback = cb.sc_next; + op->o_tag = o_tag; + return rc; } @@ -1673,18 +1740,44 @@ retry:; if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } - if ( refs != NULL ) { - int i; - - for ( i = 0; refs[ i ] != NULL; i++ ) - /* count */ ; - rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), - op->o_tmpmemctx ); - for ( i = 0; refs[ i ] != NULL; i++ ) { - ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( refs != NULL + && refs[ 0 ] != NULL + && refs[ 0 ][ 0 ] != '\0' ) + { + if ( rs->sr_err != LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_op_result: " + "got referrals with err=%d\n", + op->o_log_prefix, + rs->sr_err, 0 ); + + } else { + int i; + + for ( i = 0; refs[ i ] != NULL; i++ ) + /* count */ ; + rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), + op->o_tmpmemctx ); + for ( i = 0; refs[ i ] != NULL; i++ ) { + ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + } + BER_BVZERO( &rs->sr_ref[ i ] ); } - BER_BVZERO( &rs->sr_ref[ i ] ); + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_op_result: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + rs->sr_err, 0 ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } + if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } @@ -1739,12 +1832,14 @@ retry:; rs->sr_text = NULL; if ( rs->sr_ref ) { - assert( refs != NULL ); - ber_memvfree( (void **)refs ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } + if ( refs ) { + ber_memvfree( (void **)refs ); + } + if ( ctrls ) { assert( rs->sr_ctrls != NULL ); ldap_controls_free( ctrls ); @@ -2025,6 +2120,14 @@ ldap_back_proxy_authz_bind( li->li_idassert_authcID.bv_val, li->li_idassert_passwd.bv_val, authzID.bv_val ); + if ( defaults == NULL ) { + rs->sr_err = LDAP_OTHER; + LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + goto done; + } rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val, li->li_idassert_sasl_mech.bv_val, NULL, NULL, @@ -2128,38 +2231,19 @@ done:; */ int ldap_back_proxy_authz_ctrl( + Operation *op, + SlapReply *rs, struct berval *bound_ndn, int version, slap_idassert_t *si, - Operation *op, - SlapReply *rs, - LDAPControl ***pctrls ) + LDAPControl *ctrl ) { - LDAPControl **ctrls = NULL; - int i = 0; slap_idassert_mode_t mode; struct berval assertedID, ndn; int isroot = 0; - *pctrls = NULL; - - rs->sr_err = LDAP_SUCCESS; - - /* don't proxyAuthz if protocol is not LDAPv3 */ - switch ( version ) { - case LDAP_VERSION3: - break; - - case 0: - if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { - break; - } - /* fall thru */ - - default: - goto done; - } + rs->sr_err = SLAP_CB_CONTINUE; /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID, * but if it is not set this test fails. We need a different @@ -2232,7 +2316,7 @@ ldap_back_proxy_authz_ctrl( authcDN = ndn; } rc = slap_sasl_matches( op, si->si_authz, - &authcDN, & authcDN ); + &authcDN, &authcDN ); if ( rc != LDAP_SUCCESS ) { if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { /* ndn is not authorized @@ -2309,32 +2393,20 @@ ldap_back_proxy_authz_ctrl( goto done; } - if ( op->o_ctrls ) { - for ( i = 0; op->o_ctrls[ i ]; i++ ) - /* just count ctrls */ ; - } - - ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ), - op->o_tmpmemctx ); - ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ]; - - ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; - ctrls[ 0 ]->ldctl_iscritical = 1; - switch ( si->si_mode ) { /* already in u:ID or dn:DN form */ case LDAP_BACK_IDASSERT_OTHERID: case LDAP_BACK_IDASSERT_OTHERDN: - ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx ); + ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx ); break; /* needs the dn: prefix */ default: - ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" ); - ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1, + ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" ); + ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1, op->o_tmpmemctx ); - AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) ); - AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ], + AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) ); + AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ], assertedID.bv_val, assertedID.bv_len + 1 ); break; } @@ -2344,7 +2416,7 @@ ldap_back_proxy_authz_ctrl( * this hack provides compatibility with those DSAs that * implement it this way */ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { - struct berval authzID = ctrls[ 0 ]->ldctl_value; + struct berval authzID = ctrl->ldctl_value; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; @@ -2358,7 +2430,7 @@ ldap_back_proxy_authz_ctrl( goto free_ber; } - if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) { + if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { rs->sr_err = LDAP_OTHER; goto free_ber; } @@ -2368,22 +2440,17 @@ free_ber:; ber_free_buf( ber ); if ( rs->sr_err != LDAP_SUCCESS ) { - op->o_tmpfree( ctrls, op->o_tmpmemctx ); - ctrls = NULL; goto done; } } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { - struct berval authzID = ctrls[ 0 ]->ldctl_value, + struct berval authzID = ctrl->ldctl_value, tmp; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) { - op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx ); - op->o_tmpfree( ctrls, op->o_tmpmemctx ); - ctrls = NULL; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; } @@ -2403,7 +2470,7 @@ free_ber:; goto free_ber2; } - if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) { + if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { rs->sr_err = LDAP_OTHER; goto free_ber2; } @@ -2413,20 +2480,119 @@ free_ber2:; ber_free_buf( ber ); if ( rs->sr_err != LDAP_SUCCESS ) { - op->o_tmpfree( ctrls, op->o_tmpmemctx ); - ctrls = NULL; goto done; } - ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ; + ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ; + } + +done:; + + return rs->sr_err; +} + +/* + * Add controls; + * + * if any needs to be added, it is prepended to existing ones, + * in a newly allocated array. The companion function + * ldap_back_controls_free() must be used to restore the original + * status of op->o_ctrls. + */ +int +ldap_back_controls_add( + Operation *op, + SlapReply *rs, + ldapconn_t *lc, + LDAPControl ***pctrls ) +{ + ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; + + LDAPControl **ctrls = NULL; + /* set to the maximum number of controls this backend can add */ + LDAPControl c[ 2 ] = { 0 }; + int i = 0, j = 0; + + *pctrls = NULL; + + rs->sr_err = LDAP_SUCCESS; + + /* don't add controls if protocol is not LDAPv3 */ + switch ( li->li_version ) { + case LDAP_VERSION3: + break; + + case 0: + if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { + break; + } + /* fall thru */ + + default: + goto done; + } + + /* proxyAuthz for identity assertion */ + switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn, + li->li_version, &li->li_idassert, &c[ j ] ) ) + { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j++; + break; + + default: + goto done; + } + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + /* session tracking */ + if ( LDAP_BACK_ST_REQUEST( li ) ) { + switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j ] ) ) { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j++; + break; + + default: + goto done; + } + } +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + + if ( rs->sr_err == SLAP_CB_CONTINUE ) { + rs->sr_err = LDAP_SUCCESS; + } + + if ( j == 0 ) { + goto done; } + if ( op->o_ctrls ) { + for ( i = 0; op->o_ctrls[ i ]; i++ ) + /* just count ctrls */ ; + } + + ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + j + 1) + j * sizeof( LDAPControl ), + op->o_tmpmemctx ); + ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + j + 1 ]; + *ctrls[ 0 ] = c[ 0 ]; + for ( i = 1; i < j; i++ ) { + ctrls[ i ] = &ctrls[ 0 ][ i ]; + *ctrls[ i ] = c[ i ]; + } + + i = 0; if ( op->o_ctrls ) { for ( i = 0; op->o_ctrls[ i ]; i++ ) { - ctrls[ i + 1 ] = op->o_ctrls[ i ]; + ctrls[ i + j ] = op->o_ctrls[ i ]; } } - ctrls[ i + 1 ] = NULL; + ctrls[ i + j ] = NULL; done:; if ( ctrls == NULL ) { @@ -2439,18 +2605,25 @@ done:; } int -ldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls ) +ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ) { LDAPControl **ctrls = *pctrls; - /* we assume that the first control is the proxyAuthz - * added by back-ldap, so it's the only one we explicitly - * free */ + /* we assume that the controls added by the proxy come first, + * so as soon as we find op->o_ctrls[ 0 ] we can stop */ if ( ctrls && ctrls != op->o_ctrls ) { + int i; + assert( ctrls[ 0 ] != NULL ); - if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) { - op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx ); + for ( i = 0; ctrls[ i ] != NULL; i++ ) { + if ( op->o_ctrls && ctrls[ i ] == op->o_ctrls[ 0 ] ) { + break; + } + + if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { + op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx ); + } } op->o_tmpfree( ctrls, op->o_tmpmemctx ); diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index 3bf88376c4..509a65b187 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -112,7 +112,7 @@ static int ldap_chain_db_init_common( BackendDB *be ); static int ldap_chain_db_init_one( BackendDB *be ); static int ldap_chain_db_open_one( BackendDB *be ); #define ldap_chain_db_close_one(be) (0) -#define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) ) +#define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) ) typedef struct ldap_chain_cb_t { ldap_chain_status_t lb_status; @@ -418,7 +418,7 @@ ldap_chain_op( LDAPURLDesc *srv = NULL; struct berval save_req_dn = op->o_req_dn, save_req_ndn = op->o_req_ndn, - dn, + dn = BER_BVNULL, pdn = BER_BVNULL, ndn = BER_BVNULL; int temporary = 0; @@ -449,17 +449,24 @@ Document: RFC 4511 } /* normalize DN */ - ber_str2bv( srv->lud_dn, 0, 0, &dn ); - rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); - if ( rc == LDAP_SUCCESS ) { - /* remove DN essentially because later on - * ldap_initialize() will parse the URL - * as a comma-separated URL list */ + rc = LDAP_SUCCESS; + srv->lud_scope = LDAP_SCOPE_DEFAULT; + if ( srv->lud_dn != NULL ) { + ber_str2bv( srv->lud_dn, 0, 0, &dn ); + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); + if ( rc == LDAP_SUCCESS ) { + /* remove DN essentially because later on + * ldap_initialize() will parse the URL + * as a comma-separated URL list */ + srv->lud_dn = ""; + } + + } else { srv->lud_dn = ""; - srv->lud_scope = LDAP_SCOPE_DEFAULT; - li.li_uri = ldap_url_desc2str( srv ); - srv->lud_dn = dn.bv_val; } + + li.li_uri = ldap_url_desc2str( srv ); + srv->lud_dn = dn.bv_val; ldap_free_urldesc( srv ); if ( rc != LDAP_SUCCESS ) { @@ -500,7 +507,7 @@ Document: RFC 4511 if ( rc != 0 ) { lip->li_uri = NULL; lip->li_bvuri = NULL; - (void)ldap_chain_db_destroy_one( op->o_bd ); + (void)ldap_chain_db_destroy_one( op->o_bd, NULL); goto cleanup; } @@ -539,7 +546,7 @@ cleanup:; lip->li_uri = NULL; lip->li_bvuri = NULL; (void)ldap_chain_db_close_one( op->o_bd ); - (void)ldap_chain_db_destroy_one( op->o_bd ); + (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); } further_cleanup:; @@ -629,16 +636,19 @@ ldap_chain_search( } /* normalize DN */ - ber_str2bv( srv->lud_dn, 0, 0, &dn ); - rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); - if ( rc == LDAP_SUCCESS ) { - /* remove DN essentially because later on - * ldap_initialize() will parse the URL - * as a comma-separated URL list */ - srv->lud_dn = ""; - srv->lud_scope = LDAP_SCOPE_DEFAULT; - li.li_uri = ldap_url_desc2str( srv ); - srv->lud_dn = dn.bv_val; + rc = LDAP_INVALID_SYNTAX; + if ( srv->lud_dn != NULL ) { + ber_str2bv( srv->lud_dn, 0, 0, &dn ); + rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); + if ( rc == LDAP_SUCCESS ) { + /* remove DN essentially because later on + * ldap_initialize() will parse the URL + * as a comma-separated URL list */ + srv->lud_dn = ""; + srv->lud_scope = LDAP_SCOPE_DEFAULT; + li.li_uri = ldap_url_desc2str( srv ); + srv->lud_dn = dn.bv_val; + } } ldap_free_urldesc( srv ); @@ -681,7 +691,7 @@ ldap_chain_search( if ( rc != 0 ) { lip->li_uri = NULL; lip->li_bvuri = NULL; - (void)ldap_chain_db_destroy_one( op->o_bd ); + (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); goto cleanup; } @@ -723,7 +733,7 @@ cleanup:; lip->li_uri = NULL; lip->li_bvuri = NULL; (void)ldap_chain_db_close_one( op->o_bd ); - (void)ldap_chain_db_destroy_one( op->o_bd ); + (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); } further_cleanup:; @@ -778,7 +788,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) slap_callback *sc = op->o_callback, sc2 = { 0 }; int rc = 0; - char *text = NULL; + const char *text = NULL; const char *matched; BerVarray ref; struct berval ndn = op->o_ndn; @@ -918,6 +928,7 @@ ldap_chain_response( Operation *op, SlapReply *rs ) * to send it... */ /* FIXME: what about chaining? */ if ( rc != SLAPD_ABANDON ) { + rs->sr_err = rc; send_ldap_extended( op, rs ); rc = LDAP_SUCCESS; } @@ -1181,7 +1192,7 @@ chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) done:; if ( rc != LDAP_SUCCESS ) { - (void)ldap_chain_db_destroy_one( ca->be ); + (void)ldap_chain_db_destroy_one( ca->be, NULL ); ch_free( ca->be ); ca->be = NULL; } @@ -1206,9 +1217,9 @@ ldap_chain_cfadd_apply( void *datum, void *arg ) struct berval bv; /* FIXME: should not hardcode "olcDatabase" here */ - bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ), + bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ), "olcDatabase={%d}%s", lca->count, lback->bi_type ); - bv.bv_val = lca->ca->msg; + bv.bv_val = lca->ca->cr_msg; lca->ca->be->be_private = (void *)li; config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca, @@ -1468,11 +1479,11 @@ chain_cf_gen( ConfigArgs *c ) case CH_MAX_DEPTH: if ( c->value_int < 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid max referral depth %d", c->argv[0], c->value_int ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); rc = 1; break; } @@ -1495,7 +1506,8 @@ chain_cf_gen( ConfigArgs *c ) static int ldap_chain_db_init( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; ldap_chain_t *lc = NULL; @@ -1626,7 +1638,7 @@ private_destroy:; db.bd_info = lback; db.be_private = (void *)lc->lc_cfg_li; - ldap_chain_db_destroy_one( &db ); + ldap_chain_db_destroy_one( &db, NULL ); lc->lc_cfg_li = NULL; } else { @@ -1679,7 +1691,7 @@ ldap_chain_db_apply( void *datum, void *arg ) lca->be->be_private = (void *)li; - return lca->func( lca->be ); + return lca->func( lca->be, NULL ); } static int @@ -1702,7 +1714,7 @@ ldap_chain_db_func( db.bd_info = lback; db.be_private = lc->lc_common_li; - rc = func( &db ); + rc = func( &db, NULL ); if ( rc != 0 ) { return rc; @@ -1726,7 +1738,8 @@ ldap_chain_db_func( static int ldap_chain_db_open( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; @@ -1758,14 +1771,16 @@ ldap_chain_db_open( static int ldap_chain_db_close( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { return ldap_chain_db_func( be, db_close ); } static int ldap_chain_db_destroy( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; @@ -1797,7 +1812,7 @@ ldap_chain_db_init_common( be->bd_info = lback; be->be_private = NULL; - rc = lback->bi_db_init( be ); + rc = lback->bi_db_init( be, NULL ); if ( rc != 0 ) { return rc; } @@ -1832,7 +1847,7 @@ ldap_chain_db_init_one( be->bd_info = lback; be->be_private = NULL; - t = lback->bi_db_init( be ); + t = lback->bi_db_init( be, NULL ); if ( t != 0 ) { return t; } @@ -1876,7 +1891,7 @@ ldap_chain_db_open_one( } } - return lback->bi_db_open( be ); + return lback->bi_db_open( be, NULL ); } typedef struct ldap_chain_conn_apply_t { diff --git a/servers/slapd/back-ldap/compare.c b/servers/slapd/back-ldap/compare.c index a0a1b59807..740be24751 100644 --- a/servers/slapd/back-ldap/compare.c +++ b/servers/slapd/back-ldap/compare.c @@ -51,8 +51,7 @@ ldap_back_compare( retry: ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -69,13 +68,13 @@ retry: retrying &= ~LDAP_BACK_RETRYING; if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup: - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( lc != NULL ) { ldap_back_release_conn( li, lc ); diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 78a2f2d25c..389e17d29c 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -69,6 +69,7 @@ enum { LDAP_BACK_CFG_CONNPOOLMAX, LDAP_BACK_CFG_CANCEL, LDAP_BACK_CFG_QUARANTINE, + LDAP_BACK_CFG_ST_REQUEST, LDAP_BACK_CFG_REWRITE, LDAP_BACK_CFG_LAST @@ -183,7 +184,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "X-ORDERED 'VALUES' )", NULL, NULL }, - { "rebind-as-user", "NO|yes", 1, 2, 0, + { "rebind-as-user", "true|FALSE", 1, 2, 0, ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND, ldap_back_cf_gen, "( OLcfgDbAt:3.10 " "NAME 'olcDbRebindAsUser' " @@ -191,7 +192,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, - { "chase-referrals", "YES|no", 2, 2, 0, + { "chase-referrals", "true|FALSE", 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE, ldap_back_cf_gen, "( OLcfgDbAt:3.11 " "NAME 'olcDbChaseReferrals' " @@ -199,7 +200,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, - { "t-f-support", "NO|yes|discover", 2, 2, 0, + { "t-f-support", "true|FALSE|discover", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_T_F, ldap_back_cf_gen, "( OLcfgDbAt:3.12 " "NAME 'olcDbTFSupport' " @@ -207,7 +208,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "proxy-whoami", "NO|yes", 1, 2, 0, + { "proxy-whoami", "true|FALSE", 1, 2, 0, ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_WHOAMI, ldap_back_cf_gen, "( OLcfgDbAt:3.13 " "NAME 'olcDbProxyWhoAmI' " @@ -223,7 +224,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "idle-timeout", "timeout", 2, 0, 0, + { "idle-timeout", "timeout", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT, ldap_back_cf_gen, "( OLcfgDbAt:3.15 " "NAME 'olcDbIdleTimeout' " @@ -231,7 +232,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "conn-ttl", "ttl", 2, 0, 0, + { "conn-ttl", "ttl", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL, ldap_back_cf_gen, "( OLcfgDbAt:3.16 " "NAME 'olcDbConnTtl' " @@ -239,7 +240,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "network-timeout", "timeout", 2, 0, 0, + { "network-timeout", "timeout", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT, ldap_back_cf_gen, "( OLcfgDbAt:3.17 " "NAME 'olcDbNetworkTimeout' " @@ -247,7 +248,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "protocol-version", "version", 2, 0, 0, + { "protocol-version", "version", 2, 2, 0, ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION, ldap_back_cf_gen, "( OLcfgDbAt:3.18 " "NAME 'olcDbProtocolVersion' " @@ -255,7 +256,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, - { "single-conn", "TRUE/FALSE", 2, 0, 0, + { "single-conn", "true|FALSE", 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN, ldap_back_cf_gen, "( OLcfgDbAt:3.19 " "NAME 'olcDbSingleConn' " @@ -263,7 +264,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, - { "cancel", "ABANDON|ignore|exop", 2, 0, 0, + { "cancel", "ABANDON|ignore|exop", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_CANCEL, ldap_back_cf_gen, "( OLcfgDbAt:3.20 " "NAME 'olcDbCancel' " @@ -271,7 +272,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "quarantine", "retrylist", 2, 0, 0, + { "quarantine", "retrylist", 2, 2, 0, ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE, ldap_back_cf_gen, "( OLcfgDbAt:3.21 " "NAME 'olcDbQuarantine' " @@ -279,7 +280,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", NULL, NULL }, - { "use-temporary-conn", "TRUE/FALSE", 2, 0, 0, + { "use-temporary-conn", "true|FALSE", 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP, ldap_back_cf_gen, "( OLcfgDbAt:3.22 " "NAME 'olcDbUseTemporaryConn' " @@ -287,7 +288,7 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsBoolean " "SINGLE-VALUE )", NULL, NULL }, - { "conn-pool-max", "", 2, 0, 0, + { "conn-pool-max", "", 2, 2, 0, ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX, ldap_back_cf_gen, "( OLcfgDbAt:3.23 " "NAME 'olcDbConnectionPoolMax' " @@ -295,6 +296,16 @@ static ConfigTable ldapcfg[] = { "SYNTAX OMsInteger " "SINGLE-VALUE )", NULL, NULL }, +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + { "session-tracking-request", "true|FALSE", 2, 2, 0, + ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST, + ldap_back_cf_gen, "( OLcfgDbAt:3.24 " + "NAME 'olcDbSessionTrackingRequest' " + "DESC 'Add session tracking control to proxied requests' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL }, +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ { "suffixmassage", "[virtual]> argv[ 1 ], "dn.regex:.*" ) == 0 ) { if ( si->si_authz != NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-authzFrom \": " "\"%s\" conflicts with existing authz rules", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -567,20 +578,20 @@ slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si ) return 0; } else if ( ( si->si_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-authzFrom \": " "\"\" conflicts with \"*\"" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } ber_str2bv( c->argv[ 1 ], 0, 0, &in ); rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-authzFrom \": " "invalid syntax" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -601,11 +612,11 @@ slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si ) j = verb_to_mask( argvi, idassert_mode ); if ( BER_BVISNULL( &idassert_mode[ j ].word ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-bind \": " "unknown mode \"%s\"", argvi ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -616,11 +627,11 @@ slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si ) if ( strcasecmp( argvi, "native" ) == 0 ) { if ( si->si_bc.sb_method != LDAP_AUTH_SASL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-bind \": " "authz=\"native\" incompatible " "with auth method" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } si->si_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ; @@ -629,11 +640,11 @@ slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si ) si->si_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ; } else { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-bind \": " "unknown authz \"%s\"", argvi ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -643,11 +654,11 @@ slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si ) int j, err = 0; if ( flags == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-bind \": " "unable to parse flags \"%s\"", argvi ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -691,11 +702,11 @@ slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si ) } } else { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-bind \": " "unknown flag \"%s\"", flags[ j ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); err = 1; break; } @@ -1117,6 +1128,12 @@ ldap_back_cf_gen( ConfigArgs *c ) } break; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + case LDAP_BACK_CFG_ST_REQUEST: + c->value_int = LDAP_BACK_ST_REQUEST( li ); + break; +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + default: /* FIXME: we need to handle all... */ assert( 0 ); @@ -1233,6 +1250,12 @@ ldap_back_cf_gen( ConfigArgs *c ) li->li_flags &= ~LDAP_BACK_F_QUARANTINE; break; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + case LDAP_BACK_CFG_ST_REQUEST: + li->li_flags &= ~LDAP_BACK_F_ST_REQUEST; + break; +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + default: /* FIXME: we need to handle all... */ assert( 0 ); @@ -1297,11 +1320,11 @@ ldap_back_cf_gen( ConfigArgs *c ) why = "unknown reason"; break; } - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse uri \"%s\" " "in \"uri \" line: %s", c->value_string, why ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); urlrc = 1; goto done_url; } @@ -1317,13 +1340,13 @@ ldap_back_cf_gen( ConfigArgs *c ) || tmpludp->lud_filter != NULL || tmpludp->lud_exts != NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "warning, only protocol, " "host and port allowed " "in \"uri \" statement " "for uri #%d of \"%s\"", i, c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); } } @@ -1352,12 +1375,12 @@ ldap_back_cf_gen( ConfigArgs *c ) urllist[ i ] = ldap_url_desc2str( &tmplud ); if ( urllist[ i ] == NULL ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to rebuild uri " "in \"uri \" statement " "for \"%s\"", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); urlrc = 1; goto done_url; } @@ -1413,11 +1436,11 @@ done_url:; break; default: - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "\"acl-authcDN \" incompatible " "with auth method %d", li->li_acl_authmethod ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } if ( !BER_BVISNULL( &li->li_acl_authcDN ) ) { @@ -1439,11 +1462,11 @@ done_url:; break; default: - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"acl-passwd \" incompatible " "with auth method %d", li->li_acl_authmethod ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } if ( !BER_BVISNULL( &li->li_acl_passwd ) ) { @@ -1558,11 +1581,11 @@ done_url:; break; default: - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-authcDN \" incompatible " "with auth method %d", li->li_idassert_authmethod ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } if ( !BER_BVISNULL( &li->li_idassert_authcDN ) ) { @@ -1584,11 +1607,11 @@ done_url:; break; default: - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-passwd \" incompatible " "with auth method %d", li->li_idassert_authmethod ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } if ( !BER_BVISNULL( &li->li_idassert_passwd ) ) { @@ -1603,10 +1626,10 @@ done_url:; case LDAP_BACK_CFG_IDASSERT_METHOD: /* no longer supported */ - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"idassert-method \": " "no longer supported; use \"idassert-bind\"" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; case LDAP_BACK_CFG_IDASSERT_BIND: @@ -1649,10 +1672,10 @@ done_url:; int rc; if ( li->li_uri == NULL ) { - snprintf( c->msg, sizeof( c->msg ), - "need URI to discover \"cancel\" support " - "in \"cancel exop-discover\"" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "need URI to discover absolute filters support " + "in \"t-f-support discover\"" ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -1691,10 +1714,10 @@ done_url:; unsigned u; if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse timeout \"%s\"", c->argv[ i ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -1706,10 +1729,10 @@ done_url:; } if ( slap_cf_aux_table_parse( c->argv[ i ], li->li_timeout, timeout_table, "slapd-ldap timeout" ) ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse timeout \"%s\"", c->argv[ i ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } } @@ -1719,10 +1742,10 @@ done_url:; unsigned long t; if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse idle timeout \"%s\"", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } li->li_idle_timeout = (time_t)t; @@ -1732,10 +1755,10 @@ done_url:; unsigned long t; if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse conn ttl\"%s\"", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } li->li_conn_ttl = (time_t)t; @@ -1745,10 +1768,10 @@ done_url:; unsigned long t; if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "unable to parse network timeout \"%s\"", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } li->li_network_timeout = (time_t)t; @@ -1756,11 +1779,11 @@ done_url:; case LDAP_BACK_CFG_VERSION: if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "unsupported version \"%s\" " "in \"protocol-version \"", c->argv[ 1 ] ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -1789,7 +1812,7 @@ done_url:; if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN || c->value_int > LDAP_BACK_CONN_PRIV_MAX ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "invalid max size " "of privileged " "connections pool \"%s\" " "in \"conn-pool-max " @@ -1797,7 +1820,7 @@ done_url:; c->argv[ 1 ], LDAP_BACK_CONN_PRIV_MIN, LDAP_BACK_CONN_PRIV_MAX ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } li->li_conn_priv_max = c->value_int; @@ -1821,10 +1844,10 @@ done_url:; int rc; if ( li->li_uri == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "need URI to discover \"cancel\" support " "in \"cancel exop-discover\"" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } @@ -1847,15 +1870,15 @@ done_url:; case LDAP_BACK_CFG_QUARANTINE: if ( LDAP_BACK_QUARANTINE( li ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "quarantine already defined" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; } rc = slap_retry_info_parse( c->argv[1], &li->li_quarantine, - c->msg, sizeof( c->msg ) ); + c->cr_msg, sizeof( c->cr_msg ) ); if ( rc ) { - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); } else { ldap_pvt_thread_mutex_init( &li->li_quarantine_mutex ); @@ -1866,13 +1889,24 @@ done_url:; } break; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + case LDAP_BACK_CFG_ST_REQUEST: + if ( c->value_int ) { + li->li_flags |= LDAP_BACK_F_ST_REQUEST; + + } else { + li->li_flags &= ~LDAP_BACK_F_ST_REQUEST; + } + break; +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + case LDAP_BACK_CFG_REWRITE: - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "rewrite/remap capabilities have been moved " "to the \"rwm\" overlay; see slapo-rwm(5) " "for details (hint: add \"overlay rwm\" " "and prefix all directives with \"rwm-\")" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); return 1; default: diff --git a/servers/slapd/back-ldap/delete.c b/servers/slapd/back-ldap/delete.c index 4f1e67ddf8..f10c7d0bbb 100644 --- a/servers/slapd/back-ldap/delete.c +++ b/servers/slapd/back-ldap/delete.c @@ -50,8 +50,7 @@ ldap_back_delete( retry: ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rc = rs->sr_err; @@ -67,13 +66,13 @@ retry: retrying &= ~LDAP_BACK_RETRYING; if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup: - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( lc != NULL ) { ldap_back_release_conn( li, lc ); diff --git a/servers/slapd/back-ldap/distproc.c b/servers/slapd/back-ldap/distproc.c index 95a167f613..42424683ed 100644 --- a/servers/slapd/back-ldap/distproc.c +++ b/servers/slapd/back-ldap/distproc.c @@ -237,7 +237,7 @@ static int ldap_distproc_db_init_common( BackendDB *be ); static int ldap_distproc_db_init_one( BackendDB *be ); #define ldap_distproc_db_open_one(be) (lback)->bi_db_open( (be) ) #define ldap_distproc_db_close_one(be) (0) -#define ldap_distproc_db_destroy_one(be) (lback)->bi_db_destroy( (be) ) +#define ldap_distproc_db_destroy_one(be, ca) (lback)->bi_db_destroy( (be), (ca) ) static int ldap_distproc_parse_ctrl( @@ -447,7 +447,7 @@ distproc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) done:; if ( rc != LDAP_SUCCESS ) { - (void)ldap_distproc_db_destroy_one( ca->be ); + (void)ldap_distproc_db_destroy_one( ca->be, NULL ); ch_free( ca->be ); ca->be = NULL; } @@ -472,9 +472,9 @@ ldap_distproc_cfadd_apply( void *datum, void *arg ) struct berval bv; /* FIXME: should not hardcode "olcDatabase" here */ - bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ), + bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ), "olcDatabase={%d}%s", lca->count, lback->bi_type ); - bv.bv_val = lca->ca->msg; + bv.bv_val = lca->ca->cr_msg; lca->ca->be->be_private = (void *)li; config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca, @@ -567,7 +567,8 @@ distproc_cfgen( ConfigArgs *c ) static int ldap_distproc_db_init( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; ldap_distproc_t *lc = NULL; @@ -659,7 +660,7 @@ private_destroy:; db.bd_info = lback; db.be_private = (void *)lc->lc_cfg_li; - ldap_distproc_db_destroy_one( &db ); + ldap_distproc_db_destroy_one( &db, NULL ); lc->lc_cfg_li = NULL; } else { @@ -712,7 +713,7 @@ ldap_distproc_db_apply( void *datum, void *arg ) lca->be->be_private = (void *)li; - return lca->func( lca->be ); + return lca->func( lca->be, NULL ); } static int @@ -735,7 +736,7 @@ ldap_distproc_db_func( db.bd_info = lback; db.be_private = lc->lc_common_li; - rc = func( &db ); + rc = func( &db, NULL ); if ( rc != 0 ) { return rc; @@ -759,21 +760,24 @@ ldap_distproc_db_func( static int ldap_distproc_db_open( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { return ldap_distproc_db_func( be, db_open ); } static int ldap_distproc_db_close( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { return ldap_distproc_db_func( be, db_close ); } static int ldap_distproc_db_destroy( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; ldap_distproc_t *lc = (ldap_distproc_t *)on->on_bi.bi_private; @@ -804,7 +808,7 @@ ldap_distproc_db_init_common( be->bd_info = lback; be->be_private = NULL; - t = lback->bi_db_init( be ); + t = lback->bi_db_init( be, NULL ); if ( t != 0 ) { return t; } @@ -835,7 +839,7 @@ ldap_distproc_db_init_one( be->bd_info = lback; be->be_private = NULL; - t = lback->bi_db_init( be ); + t = lback->bi_db_init( be, NULL ); if ( t != 0 ) { return t; } diff --git a/servers/slapd/back-ldap/extended.c b/servers/slapd/back-ldap/extended.c index 38dbfcd711..cf3aacbb71 100644 --- a/servers/slapd/back-ldap/extended.c +++ b/servers/slapd/back-ldap/extended.c @@ -28,24 +28,26 @@ #include "back-ldap.h" #include "lber_pvt.h" -static BI_op_extended ldap_back_exop_passwd; -static BI_op_extended ldap_back_exop_generic; +typedef int (ldap_back_exop_f)( Operation *op, SlapReply *rs, ldapconn_t **lc ); + +static ldap_back_exop_f ldap_back_exop_passwd; +static ldap_back_exop_f ldap_back_exop_generic; static struct exop { - struct berval oid; - BI_op_extended *extended; + struct berval oid; + ldap_back_exop_f *extended; } exop_table[] = { { BER_BVC(LDAP_EXOP_MODIFY_PASSWD), ldap_back_exop_passwd }, { BER_BVNULL, NULL } }; static int -ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop ) +ldap_back_extended_one( Operation *op, SlapReply *rs, ldap_back_exop_f exop ) { ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; ldapconn_t *lc = NULL; - LDAPControl **oldctrls = NULL; + LDAPControl **ctrls = NULL, **oldctrls = NULL; int rc; /* FIXME: this needs to be called here, so it is @@ -56,9 +58,8 @@ ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop ) return -1; } - oldctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &op->o_ctrls ) ) + ctrls = op->o_ctrls; + if ( ldap_back_controls_add( op, rs, lc, &ctrls ) ) { op->o_ctrls = oldctrls; send_ldap_extended( op, rs ); @@ -68,13 +69,11 @@ ldap_back_extended_one( Operation *op, SlapReply *rs, BI_op_extended exop ) goto done; } - rc = exop( op, rs ); + op->o_ctrls = ctrls; + rc = exop( op, rs, &lc ); - if ( op->o_ctrls && op->o_ctrls != oldctrls ) { - free( op->o_ctrls[ 0 ] ); - free( op->o_ctrls ); - } op->o_ctrls = oldctrls; + (void)ldap_back_controls_free( op, rs, &ctrls ); done:; if ( lc != NULL ) { @@ -106,35 +105,90 @@ ldap_back_extended( static int ldap_back_exop_passwd( - Operation *op, - SlapReply *rs ) + Operation *op, + SlapReply *rs, + ldapconn_t **lcp ) { ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; - ldapconn_t *lc = NULL; + ldapconn_t *lc = *lcp; req_pwdexop_s *qpw = &op->oq_pwdexop; LDAPMessage *res; ber_int_t msgid; - int rc, isproxy; + int rc, isproxy, freedn = 0; int do_retry = 1; - char *text = NULL; + char *text = NULL; + struct berval dn = op->o_req_dn, + ndn = op->o_req_ndn; + + assert( lc != NULL ); + assert( rs->sr_ctrls == NULL ); + + if ( BER_BVISNULL( &ndn ) && op->ore_reqdata != NULL ) { + /* NOTE: most of this code is mutuated + * from slap_passwd_parse(); we can't call + * that function since now the request data + * has been destroyed by NULL-terminating + * the bervals. Luckily enough, we only need + * the first berval... */ + + ber_tag_t tag; + ber_len_t len = -1; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + struct berval tmpid = BER_BVNULL; + + if ( op->ore_reqdata->bv_len == 0 ) { + return LDAP_PROTOCOL_ERROR; + } - if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) { - return -1; + /* ber_init2 uses reqdata directly, doesn't allocate new buffers */ + ber_init2( ber, op->ore_reqdata, 0 ); + + tag = ber_scanf( ber, "{" /*}*/ ); + + if ( tag == LBER_ERROR ) { + return LDAP_PROTOCOL_ERROR; + } + + tag = ber_peek_tag( ber, &len ); + if ( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) { + tag = ber_scanf( ber, "m", &tmpid ); + + if ( tag == LBER_ERROR ) { + return LDAP_PROTOCOL_ERROR; + } + } + + if ( !BER_BVISEMPTY( &tmpid ) ) { + rs->sr_err = dnPrettyNormal( NULL, &tmpid, &dn, + &ndn, op->o_tmpmemctx ); + if ( rs->sr_err != LDAP_SUCCESS ) { + /* should have been successfully parsed earlier! */ + return rs->sr_err; + } + freedn = 1; + + } else { + dn = op->o_dn; + ndn = op->o_ndn; + } } - isproxy = ber_bvcmp( &op->o_req_ndn, &op->o_ndn ); + isproxy = ber_bvcmp( &ndn, &op->o_ndn ); Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_passwd(\"%s\")%s\n", - op->o_req_dn.bv_val, isproxy ? " (proxy)" : "", 0 ); + dn.bv_val, isproxy ? " (proxy)" : "", 0 ); retry: - rc = ldap_passwd( lc->lc_ld, isproxy ? &op->o_req_dn : NULL, + rc = ldap_passwd( lc->lc_ld, isproxy ? &dn : NULL, qpw->rs_old.bv_val ? &qpw->rs_old : NULL, qpw->rs_new.bv_val ? &qpw->rs_new : NULL, op->o_ctrls, NULL, &msgid ); if ( rc == LDAP_SUCCESS ) { + /* TODO: set timeout? */ if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) { ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc ); rs->sr_err = rc; @@ -151,7 +205,7 @@ retry: rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, (char **)&rs->sr_matched, &text, - NULL, NULL, 0 ); + NULL, &rs->sr_ctrls, 0 ); if ( rc == LDAP_SUCCESS ) { if ( rs->sr_err == LDAP_SUCCESS ) { @@ -204,19 +258,30 @@ retry: ldap_back_quarantine( op, rs ); } + if ( freedn ) { + op->o_tmpfree( dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); + } + /* these have to be freed anyway... */ if ( rs->sr_matched ) { free( (char *)rs->sr_matched ); rs->sr_matched = NULL; } + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + if ( text ) { free( text ); rs->sr_text = NULL; } - if ( lc != NULL ) { - ldap_back_release_conn( li, lc ); + /* in case, cleanup handler */ + if ( lc == NULL ) { + *lcp = NULL; } return rc; @@ -225,20 +290,20 @@ retry: static int ldap_back_exop_generic( Operation *op, - SlapReply *rs ) + SlapReply *rs, + ldapconn_t **lcp ) { ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; - ldapconn_t *lc = NULL; + ldapconn_t *lc = *lcp; LDAPMessage *res; ber_int_t msgid; int rc; int do_retry = 1; - char *text = NULL; + char *text = NULL; - if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) { - return -1; - } + assert( lc != NULL ); + assert( rs->sr_ctrls == NULL ); Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_generic(%s, \"%s\")\n", op->ore_reqoid.bv_val, op->o_req_dn.bv_val, 0 ); @@ -249,6 +314,7 @@ retry: op->o_ctrls, NULL, &msgid ); if ( rc == LDAP_SUCCESS ) { + /* TODO: set timeout? */ if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) { ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc ); rs->sr_err = rc; @@ -265,7 +331,7 @@ retry: rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, (char **)&rs->sr_matched, &text, - NULL, NULL, 0 ); + NULL, &rs->sr_ctrls, 0 ); if ( rc == LDAP_SUCCESS ) { if ( rs->sr_err == LDAP_SUCCESS ) { rc = ldap_parse_extended_result( lc->lc_ld, res, @@ -310,13 +376,19 @@ retry: rs->sr_matched = NULL; } + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + if ( text ) { free( text ); rs->sr_text = NULL; } - if ( lc != NULL ) { - ldap_back_release_conn( li, lc ); + /* in case, cleanup handler */ + if ( lc == NULL ) { + *lcp = NULL; } return rc; diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index d9a4ff61c4..32b07b2f8c 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -29,6 +29,7 @@ #include #include "slap.h" +#include "config.h" #include "back-ldap.h" int @@ -98,7 +99,7 @@ ldap_back_initialize( BackendInfo *bi ) } int -ldap_back_db_init( Backend *be ) +ldap_back_db_init( Backend *be, ConfigReply *cr ) { ldapinfo_t *li; int rc; @@ -168,7 +169,7 @@ ldap_back_db_init( Backend *be ) } int -ldap_back_db_open( BackendDB *be ) +ldap_back_db_open( BackendDB *be, ConfigReply *cr ) { ldapinfo_t *li = (ldapinfo_t *)be->be_private; @@ -255,7 +256,7 @@ ldap_back_conn_free( void *v_lc ) } int -ldap_back_db_close( Backend *be ) +ldap_back_db_close( Backend *be, ConfigReply *cr ) { int rc = 0; @@ -267,7 +268,7 @@ ldap_back_db_close( Backend *be ) } int -ldap_back_db_destroy( Backend *be ) +ldap_back_db_destroy( Backend *be, ConfigReply *cr ) { if ( be->be_private ) { ldapinfo_t *li = ( ldapinfo_t * )be->be_private; diff --git a/servers/slapd/back-ldap/modify.c b/servers/slapd/back-ldap/modify.c index 3c287cd8db..7b5817f066 100644 --- a/servers/slapd/back-ldap/modify.c +++ b/servers/slapd/back-ldap/modify.c @@ -52,7 +52,7 @@ ldap_back_modify( return rs->sr_err; } - for ( i = 0, ml = op->oq_modify.rs_modlist; ml; i++, ml = ml->sml_next ) + for ( i = 0, ml = op->orm_modlist; ml; i++, ml = ml->sml_next ) /* just count mods */ ; modv = (LDAPMod **)ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) @@ -64,7 +64,7 @@ ldap_back_modify( mods = (LDAPMod *)&modv[ i + 1 ]; isupdate = be_shadow_update( op ); - for ( i = 0, ml = op->oq_modify.rs_modlist; ml; ml = ml->sml_next ) { + for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) { if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod ) { continue; @@ -99,8 +99,7 @@ ldap_back_modify( retry:; ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rc = -1; @@ -116,13 +115,13 @@ retry:; retrying &= ~LDAP_BACK_RETRYING; if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); for ( i = 0; modv[ i ]; i++ ) { ch_free( modv[ i ]->mod_bvalues ); diff --git a/servers/slapd/back-ldap/modrdn.c b/servers/slapd/back-ldap/modrdn.c index 8fa02ef6e2..d6e3b01854 100644 --- a/servers/slapd/back-ldap/modrdn.c +++ b/servers/slapd/back-ldap/modrdn.c @@ -74,8 +74,7 @@ ldap_back_modrdn( retry: ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rc = -1; @@ -92,13 +91,13 @@ retry: retrying &= ~LDAP_BACK_RETRYING; if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup: - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( lc != NULL ) { ldap_back_release_conn( li, lc ); diff --git a/servers/slapd/back-ldap/proto-ldap.h b/servers/slapd/back-ldap/proto-ldap.h index 8eca7f6593..9bc4133387 100644 --- a/servers/slapd/back-ldap/proto-ldap.h +++ b/servers/slapd/back-ldap/proto-ldap.h @@ -63,6 +63,7 @@ extern void ldap_back_conn_free( void *c ); extern ldapconn_t * ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc ); +#if 0 extern int ldap_back_proxy_authz_ctrl( struct berval *bound_ndn, @@ -76,6 +77,26 @@ extern int ldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls ); +#endif + +extern int +ldap_back_proxy_authz_ctrl( + Operation *op, + SlapReply *rs, + struct berval *bound_ndn, + int version, + slap_idassert_t *si, + LDAPControl *ctrl ); + +extern int +ldap_back_controls_add( + Operation *op, + SlapReply *rs, + ldapconn_t *lc, + LDAPControl ***pctrls ); + +extern int +ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ); extern void ldap_back_quarantine( diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 1154d44d82..4c4f078fb1 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -158,6 +158,8 @@ ldap_back_search( int freetext = 0; int do_retry = 1, dont_retry = 0; LDAPControl **ctrls = NULL; + char **references = NULL; + /* FIXME: shouldn't this be null? */ const char *save_matched = rs->sr_matched; @@ -203,8 +205,7 @@ ldap_back_search( } ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, rs, &ctrls ); + rc = ldap_back_controls_add( op, rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { goto finish; } @@ -328,12 +329,18 @@ retry: e = ldap_first_entry( lc->lc_ld, res ); rc = ldap_build_entry( op, e, &ent, &bdn ); if ( rc == LDAP_SUCCESS ) { + ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls ); rs->sr_entry = &ent; rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_flags = 0; rs->sr_err = LDAP_SUCCESS; rc = rs->sr_err = send_search_entry( op, rs ); + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + rs->sr_entry = NULL; if ( !BER_BVISNULL( &ent.e_name ) ) { assert( ent.e_name.bv_val != bdn.bv_val ); op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx ); @@ -356,8 +363,6 @@ retry: } } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) { - char **references = NULL; - do_retry = 0; rc = ldap_parse_reference( lc->lc_ld, res, &references, &rs->sr_ctrls, 1 ); @@ -383,6 +388,7 @@ retry: BER_BVZERO( &rs->sr_ref[ cnt ] ); /* ignore return value by now */ + rs->sr_entry = NULL; ( void )send_search_reference( op, rs ); } else { @@ -398,6 +404,7 @@ retry: ber_memvfree( (void **)references ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; + references = NULL; } if ( rs->sr_ctrls ) { @@ -406,7 +413,7 @@ retry: } } else { - char **references = NULL, *err = NULL; + char *err = NULL; rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, &match.bv_val, &err, @@ -420,41 +427,50 @@ retry: freetext = 1; } - if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { - int cnt; - + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( references + && references[ 0 ] + && references[ 0 ][ 0 ] ) + { if ( rs->sr_err != LDAP_REFERRAL ) { - /* FIXME: error */ Debug( LDAP_DEBUG_ANY, "%s ldap_back_search: " - "got referrals with %d\n", + "got referrals with err=%d\n", op->o_log_prefix, rs->sr_err, 0 ); - rs->sr_err = LDAP_REFERRAL; - } - for ( cnt = 0; references[ cnt ]; cnt++ ) - /* NO OP */ ; + } else { + int cnt; + + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; - rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ), - op->o_tmpmemctx ); + rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ), + op->o_tmpmemctx ); - for ( cnt = 0; references[ cnt ]; cnt++ ) { - /* duplicating ...*/ - ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] ); + for ( cnt = 0; references[ cnt ]; cnt++ ) { + /* duplicating ...*/ + ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); + } + BER_BVZERO( &rs->sr_ref[ cnt ] ); } - BER_BVZERO( &rs->sr_ref[ cnt ] ); + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_search: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + rs->sr_err, 0 ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } if ( match.bv_val != NULL ) { match.bv_len = strlen( match.bv_val ); } - /* cleanup */ - if ( references ) { - ber_memvfree( (void **)references ); - } - rc = 0; break; } @@ -512,7 +528,7 @@ finish:; send_ldap_result( op, rs ); } - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( rs->sr_ctrls ) { ldap_controls_free( rs->sr_ctrls ); @@ -541,10 +557,14 @@ finish:; } if ( rs->sr_ref ) { - ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx ); + op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); rs->sr_ref = NULL; } + if ( references ) { + ber_memvfree( (void **)references ); + } + if ( attrs ) { ch_free( attrs ); } @@ -798,8 +818,7 @@ ldap_back_entry_get( retry: ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &lc->lc_bound_ndn, - li->li_version, &li->li_idassert, op, &rs, &ctrls ); + rc = ldap_back_controls_add( op, &rs, lc, &ctrls ); if ( rc != LDAP_SUCCESS ) { goto cleanup; } @@ -812,7 +831,7 @@ retry: do_retry = 0; if ( ldap_back_retry( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, &rs, &ctrls ); goto retry; } } @@ -839,7 +858,7 @@ retry: } cleanup: - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, &rs, &ctrls ); if ( result ) { ldap_msgfree( result ); diff --git a/servers/slapd/back-ldif/ldif.c b/servers/slapd/back-ldif/ldif.c index 855e63889f..4ad7603367 100644 --- a/servers/slapd/back-ldif/ldif.c +++ b/servers/slapd/back-ldif/ldif.c @@ -86,7 +86,6 @@ dn2path(struct berval * dn, struct berval * suffixdn, struct berval * base_path, struct berval *res) { char *ptr, *sep, *end; - struct berval bv; assert( dn != NULL ); assert( !BER_BVISNULL( dn ) ); @@ -108,19 +107,22 @@ dn2path(struct berval * dn, struct berval * suffixdn, struct berval * base_path, } strcpy(ptr, LDIF); #if IX_FSL != IX_DNL - bv = *res; - while ( ptr = ber_bvchr( &bv, IX_DNL ) ) { - *ptr++ = IX_FSL; - assert( ( ptr - bv.bv_val ) <= bv.bv_len ); - bv.bv_len -= ( ptr - bv.bv_val ); - bv.bv_val = ptr; - ptr = ber_bvchr( &bv, IX_DNR ); - if ( !ptr ) - break; - *ptr++ = IX_FSR; - assert( ( ptr - bv.bv_val ) <= bv.bv_len ); - bv.bv_len -= ( ptr - bv.bv_val ); - bv.bv_val = ptr; + { + struct berval bv; + bv = *res; + while ( ptr = ber_bvchr( &bv, IX_DNL ) ) { + *ptr++ = IX_FSL; + assert( ( ptr - bv.bv_val ) <= bv.bv_len ); + bv.bv_len -= ( ptr - bv.bv_val ); + bv.bv_val = ptr; + ptr = ber_bvchr( &bv, IX_DNR ); + if ( !ptr ) + break; + *ptr++ = IX_FSR; + assert( ( ptr - bv.bv_val ) <= bv.bv_len ); + bv.bv_len -= ( ptr - bv.bv_val ); + bv.bv_val = ptr; + } } #endif } @@ -156,14 +158,16 @@ static char * slurp_file(int fd) { return entry; } +/* + * return number of bytes written, or -1 in case of error + * do not return numbers less than -1 + */ static int spew_file(int fd, char * spew, int len) { int writeres = 0; while(len > 0) { writeres = write(fd, spew, len); if(writeres == -1) { - Debug( LDAP_DEBUG_ANY, "could not spew write: %s\n", - STRERROR( errno ), 0, 0 ); return -1; } else { @@ -174,23 +178,28 @@ static int spew_file(int fd, char * spew, int len) { return writeres; } -static int spew_entry(Entry * e, struct berval * path) { - int rs; +static int +spew_entry( Entry * e, struct berval * path, int dolock, int *save_errnop ) +{ + int rs, save_errno = 0; int openres; - int spew_res; + int res, spew_res; int entry_length; char * entry_as_string; + char *tmpfname = NULL; - openres = open(path->bv_val, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD | S_IWRITE); - if(openres == -1) { - if(errno == ENOENT) - rs = LDAP_NO_SUCH_OBJECT; - else - rs = LDAP_UNWILLING_TO_PERFORM; - Debug( LDAP_DEBUG_ANY, "could not open \"%s\": %s\n", - path->bv_val, STRERROR( errno ), 0 ); - } - else { + tmpfname = ch_malloc( path->bv_len + STRLENOF( "XXXXXX" ) + 1 ); + AC_MEMCPY( tmpfname, path->bv_val, path->bv_len ); + AC_MEMCPY( &tmpfname[ path->bv_len ], "XXXXXX", STRLENOF( "XXXXXX" ) + 1 ); + + openres = mkstemp( tmpfname ); + if ( openres == -1 ) { + save_errno = errno; + rs = LDAP_UNWILLING_TO_PERFORM; + Debug( LDAP_DEBUG_ANY, "could not create tmpfile \"%s\": %s\n", + tmpfname, STRERROR( save_errno ), 0 ); + + } else { struct berval rdn; int tmp; @@ -203,7 +212,23 @@ static int spew_entry(Entry * e, struct berval * path) { rdn.bv_len = tmp; } + spew_res = -2; + if ( dolock ) { + ldap_pvt_thread_mutex_lock(&entry2str_mutex); + } + entry_as_string = entry2str(e, &entry_length); + if ( entry_as_string != NULL ) { + spew_res = spew_file( openres, + entry_as_string, entry_length ); + if ( spew_res == -1 ) { + save_errno = errno; + } + } + + if ( dolock ) { + ldap_pvt_thread_mutex_unlock(&entry2str_mutex); + } /* Restore full DN */ if ( rdn.bv_len != e->e_name.bv_len ) { @@ -211,19 +236,47 @@ static int spew_entry(Entry * e, struct berval * path) { e->e_name.bv_len = rdn.bv_len; } - if(entry_as_string == NULL) { - rs = LDAP_UNWILLING_TO_PERFORM; - close(openres); + res = close( openres ); + rs = LDAP_UNWILLING_TO_PERFORM; + + if ( spew_res > -2 ) { + if ( res == -1 || spew_res == -1 ) { + if ( save_errno == 0 ) { + save_errno = errno; + } + Debug( LDAP_DEBUG_ANY, "write error to tmpfile \"%s\": %s\n", + tmpfname, STRERROR( save_errno ), 0 ); + + } else { + res = rename( tmpfname, path->bv_val ); + if ( res == 0 ) { + rs = LDAP_SUCCESS; + + } else { + save_errno = errno; + switch ( save_errno ) { + case ENOENT: + rs = LDAP_NO_SUCH_OBJECT; + break; + + default: + break; + } + } + } } - else { - spew_res = spew_file(openres, entry_as_string, entry_length); - close(openres); - if(spew_res == -1) - rs = LDAP_UNWILLING_TO_PERFORM; - else - rs = LDAP_SUCCESS; + + if ( rs != LDAP_SUCCESS ) { + unlink( tmpfname ); } } + + ch_free( tmpfname ); + + if ( rs != LDAP_SUCCESS && save_errnop != NULL ) { + *save_errnop = save_errno; + } + return rs; } @@ -299,7 +352,7 @@ typedef struct bvlist { struct bvlist *next; struct berval bv; struct berval num; - unsigned int inum; + int inum; int off; } bvlist; @@ -481,14 +534,14 @@ enum_tree( enumCookie *ck ) { - struct ldif_info *ni = (struct ldif_info *) ck->op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) ck->op->o_bd->be_private; struct berval path; struct berval pdn, pndn; int rc; dnParent( &ck->op->o_req_dn, &pdn ); dnParent( &ck->op->o_req_ndn, &pndn ); - dn2path( &ck->op->o_req_ndn, &ck->op->o_bd->be_nsuffix[0], &ni->li_base_path, &path); + dn2path( &ck->op->o_req_ndn, &ck->op->o_bd->be_nsuffix[0], &li->li_base_path, &path); rc = r_enum_tree(ck, &path, &pdn, &pndn); ch_free( path.bv_val ); return rc; @@ -592,7 +645,7 @@ static int apply_modify_to_entry(Entry * entry, int ldif_back_referrals( Operation *op, SlapReply *rs ) { - struct ldif_info *ni = NULL; + struct ldif_info *li = NULL; Entry *entry; int rc = LDAP_SUCCESS; @@ -608,9 +661,9 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) return rc; } - ni = (struct ldif_info *)op->o_bd->be_private; - ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr ); - entry = (Entry *)get_entry( op, &ni->li_base_path ); + li = (struct ldif_info *)op->o_bd->be_private; + ldap_pvt_thread_rdwr_rlock( &li->li_rdwr ); + entry = get_entry( op, &li->li_base_path ); /* no object is found for them */ if ( entry == NULL ) { @@ -629,10 +682,10 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) op->o_req_dn = pndn; op->o_req_ndn = pndn; - entry = (Entry *)get_entry( op, &ni->li_base_path ); + entry = get_entry( op, &li->li_base_path ); } - ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr ); + ldap_pvt_thread_rdwr_runlock( &li->li_rdwr ); op->o_req_dn = odn; op->o_req_ndn = ondn; @@ -641,8 +694,8 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) rs->sr_matched = NULL; if ( entry != NULL ) { Debug( LDAP_DEBUG_TRACE, - "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", - (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val ); + "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n", + (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val ); if ( is_entry_referral( entry ) ) { rc = LDAP_OTHER; @@ -682,7 +735,7 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) return rc; } - ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr ); + ldap_pvt_thread_rdwr_runlock( &li->li_rdwr ); if ( is_entry_referral( entry ) ) { /* entry is a referral */ @@ -691,8 +744,8 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) refs, &entry->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); Debug( LDAP_DEBUG_TRACE, - "ldif_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", - (long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val ); + "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n", + (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_name.bv_val ); rs->sr_matched = entry->e_name.bv_val; if ( rs->sr_ref != NULL ) { @@ -718,23 +771,29 @@ ldif_back_referrals( Operation *op, SlapReply *rs ) static int ldif_back_bind( Operation *op, SlapReply *rs ) { - struct ldif_info *ni = NULL; + struct ldif_info *li = NULL; Attribute * a = NULL; AttributeDescription *password = slap_schema.si_ad_userPassword; int return_val = 0; Entry * entry = NULL; - ni = (struct ldif_info *) op->o_bd->be_private; - ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr); - entry = (Entry *) get_entry(op, &ni->li_base_path); + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + /* in case of success, front end will send result; + * otherwise, be_rootdn_bind() did */ + return rs->sr_err; + } + + li = (struct ldif_info *) op->o_bd->be_private; + ldap_pvt_thread_rdwr_rlock(&li->li_rdwr); + entry = get_entry(op, &li->li_base_path); /* no object is found for them */ if(entry == NULL) { - if(be_isroot_pw(op)) { - rs->sr_err = return_val = LDAP_SUCCESS; - } else { - rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS; - } + rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS; goto return_result; } @@ -758,7 +817,7 @@ ldif_back_bind( Operation *op, SlapReply *rs ) goto return_result; return_result: - ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_runlock(&li->li_rdwr); if(return_val != 0) send_ldap_result( op, rs ); if(entry != NULL) @@ -768,21 +827,21 @@ ldif_back_bind( Operation *op, SlapReply *rs ) static int ldif_back_search(Operation *op, SlapReply *rs) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; enumCookie ck = { NULL, NULL, NULL, 0, 0 }; ck.op = op; ck.rs = rs; - ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_rlock(&li->li_rdwr); rs->sr_err = enum_tree( &ck ); - ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_runlock(&li->li_rdwr); send_ldap_result(op, rs); return rs->sr_err; } static int ldif_back_add(Operation *op, SlapReply *rs) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; Entry * e = op->ora_e; struct berval dn = e->e_nname; struct berval leaf_path = BER_BVNULL; @@ -800,9 +859,9 @@ static int ldif_back_add(Operation *op, SlapReply *rs) { &rs->sr_text, textbuf, sizeof( textbuf ), 1 ); if ( rs->sr_err != LDAP_SUCCESS ) goto send_res; - ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_wlock(&li->li_rdwr); - dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path); + dn2path(&dn, &op->o_bd->be_nsuffix[0], &li->li_base_path, &leaf_path); if(leaf_path.bv_val != NULL) { struct berval base = BER_BVNULL; @@ -833,9 +892,7 @@ static int ldif_back_add(Operation *op, SlapReply *rs) { if(rs->sr_err == LDAP_SUCCESS) { statres = stat(leaf_path.bv_val, &stats); if(statres == -1 && errno == ENOENT) { - ldap_pvt_thread_mutex_lock(&entry2str_mutex); - rs->sr_err = (int) spew_entry(e, &leaf_path); - ldap_pvt_thread_mutex_unlock(&entry2str_mutex); + rs->sr_err = spew_entry(e, &leaf_path, 1, NULL); } else if ( statres == -1 ) { rs->sr_err = LDAP_UNWILLING_TO_PERFORM; @@ -849,7 +906,7 @@ static int ldif_back_add(Operation *op, SlapReply *rs) { SLAP_FREE(leaf_path.bv_val); } - ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr); send_res: Debug( LDAP_DEBUG_TRACE, @@ -857,11 +914,11 @@ send_res: rs->sr_text : "", 0); send_ldap_result(op, rs); slap_graduate_commit_csn( op ); - return 0; + return rs->sr_err; } static int ldif_back_modify(Operation *op, SlapReply *rs) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; Modifications * modlst = op->orm_modlist; struct berval path = BER_BVNULL; Entry * entry = NULL; @@ -869,19 +926,16 @@ static int ldif_back_modify(Operation *op, SlapReply *rs) { slap_mods_opattrs( op, &op->orm_modlist, 1 ); - ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr); - dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, + ldap_pvt_thread_rdwr_wlock(&li->li_rdwr); + dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &li->li_base_path, &path); - entry = (Entry *) get_entry(op, &ni->li_base_path); + entry = get_entry(op, &li->li_base_path); if(entry != NULL) { rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs); if(rs->sr_err == LDAP_SUCCESS) { int save_errno; - ldap_pvt_thread_mutex_lock(&entry2str_mutex); - spew_res = spew_entry(entry, &path); - save_errno = errno; - ldap_pvt_thread_mutex_unlock(&entry2str_mutex); + spew_res = spew_entry(entry, &path, 1, &save_errno); if(spew_res == -1) { Debug( LDAP_DEBUG_ANY, "%s ldif_back_modify: could not output entry \"%s\": %s\n", @@ -899,14 +953,14 @@ static int ldif_back_modify(Operation *op, SlapReply *rs) { if(path.bv_val != NULL) SLAP_FREE(path.bv_val); rs->sr_text = NULL; - ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr); send_ldap_result(op, rs); slap_graduate_commit_csn( op ); - return 0; + return rs->sr_err; } static int ldif_back_delete(Operation *op, SlapReply *rs) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; struct berval path = BER_BVNULL; int res = 0; @@ -919,32 +973,48 @@ static int ldif_back_delete(Operation *op, SlapReply *rs) { slap_get_csn( op, &csn, 1 ); } - ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr); - dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path); + ldap_pvt_thread_rdwr_wlock(&li->li_rdwr); + dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &li->li_base_path, &path); path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0'; res = rmdir(path.bv_val); path.bv_val[path.bv_len - STRLENOF(LDIF)] = '.'; - if ( res && errno != ENOENT ) { - rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; - } else { - res = unlink(path.bv_val); - } + rs->sr_err = LDAP_SUCCESS; + if ( res ) { + switch ( errno ) { + case ENOTEMPTY: + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + break; - if(res == -1) { - if(errno == ENOENT) + case ENOENT: rs->sr_err = LDAP_NO_SUCH_OBJECT; - else + break; + + default: rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + break; + } + + } else { + res = unlink(path.bv_val); + if ( res == -1 ) { + switch ( errno ) { + case ENOENT: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + break; + + default: + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + break; + } + } } - else - rs->sr_err = LDAP_SUCCESS; SLAP_FREE(path.bv_val); - ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr); + ldap_pvt_thread_rdwr_wunlock(&li->li_rdwr); send_ldap_result(op, rs); slap_graduate_commit_csn( op ); - return 0; + return rs->sr_err; } @@ -967,7 +1037,7 @@ static int move_entry(Entry * entry, struct berval * ndn, exists_res = open(newpath.bv_val, O_RDONLY); if(exists_res == -1 && errno == ENOENT) { ldap_pvt_thread_mutex_lock( &entry2str_mutex ); - res = spew_entry(entry, &newpath); + res = spew_entry(entry, &newpath, 0, NULL); if(res != -1) { /* if this fails we should log something bad */ res = unlink(path.bv_val); @@ -1007,7 +1077,7 @@ static int move_entry(Entry * entry, struct berval * ndn, static int ldif_back_modrdn(Operation *op, SlapReply *rs) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL; struct berval p_dn; Entry * entry = NULL; @@ -1015,8 +1085,8 @@ ldif_back_modrdn(Operation *op, SlapReply *rs) slap_mods_opattrs( op, &op->orr_modlist, 1 ); - ldap_pvt_thread_rdwr_wlock( &ni->li_rdwr ); - entry = (Entry *) get_entry( op, &ni->li_base_path ); + ldap_pvt_thread_rdwr_wlock( &li->li_rdwr ); + entry = get_entry( op, &li->li_base_path ); /* build the mods to the entry */ if ( entry != NULL ) { @@ -1030,7 +1100,7 @@ ldif_back_modrdn(Operation *op, SlapReply *rs) p_dn = *op->oq_modrdn.rs_newSup; op->o_req_dn = *op->oq_modrdn.rs_newSup; op->o_req_ndn = *op->oq_modrdn.rs_nnewSup; - np = (Entry *)get_entry( op, &ni->li_base_path ); + np = get_entry( op, &li->li_base_path ); op->o_req_dn = op_dn; op->o_req_ndn = op_ndn; if ( np == NULL ) { @@ -1053,7 +1123,7 @@ ldif_back_modrdn(Operation *op, SlapReply *rs) rs->sr_err = move_entry( entry, &op->o_req_ndn, &new_ndn, &op->o_bd->be_nsuffix[0], - &ni->li_base_path ); + &li->li_base_path ); } else { rs->sr_err = res; } @@ -1067,10 +1137,10 @@ no_such_object:; entry_free( entry ); } rs->sr_text = ""; - ldap_pvt_thread_rdwr_wunlock( &ni->li_rdwr ); + ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr ); send_ldap_result( op, rs ); slap_graduate_commit_csn( op ); - return 0; + return rs->sr_err; } /* return LDAP_SUCCESS IFF we can retrieve the specified entry. @@ -1083,19 +1153,19 @@ int ldif_back_entry_get( int rw, Entry **ent ) { - struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private; + struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn; assert( ndn != NULL ); assert( !BER_BVISNULL( ndn ) ); - ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr ); + ldap_pvt_thread_rdwr_rlock( &li->li_rdwr ); op->o_req_dn = *ndn; op->o_req_ndn = *ndn; - *ent = (Entry *) get_entry( op, &ni->li_base_path ); + *ent = get_entry( op, &li->li_base_path ); op->o_req_dn = op_dn; op->o_req_ndn = op_ndn; - ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr ); + ldap_pvt_thread_rdwr_runlock( &li->li_rdwr ); if ( *ent && oc && !is_entry_objectclass_or_sub( *ent, oc ) ) { entry_free( *ent ); @@ -1105,72 +1175,69 @@ int ldif_back_entry_get( return ( *ent == NULL ? 1 : 0 ); } -static int ldif_tool_entry_open(BackendDB * be, int mode) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; - ni->li_tool_current = 0; +static int ldif_tool_entry_open(BackendDB *be, int mode) { + struct ldif_info *li = (struct ldif_info *) be->be_private; + li->li_tool_current = 0; return 0; } static int ldif_tool_entry_close(BackendDB * be) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; + struct ldif_info *li = (struct ldif_info *) be->be_private; - SLAP_FREE(ni->li_tool_cookie.entries); + SLAP_FREE(li->li_tool_cookie.entries); return 0; } +static ID ldif_tool_entry_next(BackendDB *be) +{ + struct ldif_info *li = (struct ldif_info *) be->be_private; + if(li->li_tool_current >= li->li_tool_cookie.eind) + return NOID; + else + return ++li->li_tool_current; +} + static ID ldif_tool_entry_first(BackendDB *be) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; - ID id = 1; /* first entry in the array of entries shifted by one */ + struct ldif_info *li = (struct ldif_info *) be->be_private; - ni->li_tool_current = 1; - if(ni->li_tool_cookie.entries == NULL) { + if(li->li_tool_cookie.entries == NULL) { Operation op = {0}; op.o_bd = be; op.o_req_dn = *be->be_suffix; op.o_req_ndn = *be->be_nsuffix; op.ors_scope = LDAP_SCOPE_SUBTREE; - ni->li_tool_cookie.op = &op; - (void)enum_tree( &ni->li_tool_cookie ); - ni->li_tool_cookie.op = NULL; + li->li_tool_cookie.op = &op; + (void)enum_tree( &li->li_tool_cookie ); + li->li_tool_cookie.op = NULL; } - return id; -} - -static ID ldif_tool_entry_next(BackendDB *be) -{ - struct ldif_info *ni = (struct ldif_info *) be->be_private; - ni->li_tool_current += 1; - if(ni->li_tool_current > ni->li_tool_cookie.eind) - return NOID; - else - return ni->li_tool_current; + return ldif_tool_entry_next( be ); } static Entry * ldif_tool_entry_get(BackendDB * be, ID id) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; + struct ldif_info *li = (struct ldif_info *) be->be_private; Entry * e; - if(id > ni->li_tool_cookie.eind || id < 1) + if(id > li->li_tool_cookie.eind || id < 1) return NULL; else { - e = ni->li_tool_cookie.entries[id - 1]; - ni->li_tool_cookie.entries[id - 1] = NULL; + e = li->li_tool_cookie.entries[id - 1]; + li->li_tool_cookie.entries[id - 1] = NULL; return e; } } static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; + struct ldif_info *li = (struct ldif_info *) be->be_private; struct berval dn = e->e_nname; struct berval leaf_path = BER_BVNULL; struct stat stats; int statres; int res = LDAP_SUCCESS; - dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path, &leaf_path); + dn2path(&dn, &be->be_nsuffix[0], &li->li_base_path, &leaf_path); if(leaf_path.bv_val != NULL) { struct berval base = BER_BVNULL; @@ -1197,7 +1264,7 @@ static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) { if(res == LDAP_SUCCESS) { statres = stat(leaf_path.bv_val, &stats); if(statres == -1 && errno == ENOENT) { - res = (int) spew_entry(e, &leaf_path); + res = spew_entry(e, &leaf_path, 0, NULL); } else /* it already exists */ res = LDAP_ALREADY_EXISTS; @@ -1214,37 +1281,33 @@ static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) { } static int -ldif_back_db_init( BackendDB *be ) +ldif_back_db_init( BackendDB *be, ConfigReply *cr ) { - struct ldif_info *ni; + struct ldif_info *li; - ni = ch_calloc( 1, sizeof(struct ldif_info) ); - be->be_private = ni; + li = ch_calloc( 1, sizeof(struct ldif_info) ); + be->be_private = li; be->be_cf_ocs = ldifocs; - ldap_pvt_thread_rdwr_init(&ni->li_rdwr); + ldap_pvt_thread_rdwr_init(&li->li_rdwr); return 0; } static int -ldif_back_db_destroy( - Backend *be - ) +ldif_back_db_destroy( Backend *be, ConfigReply *cr ) { - struct ldif_info *ni = be->be_private; + struct ldif_info *li = be->be_private; - ch_free(ni->li_base_path.bv_val); - ldap_pvt_thread_rdwr_destroy(&ni->li_rdwr); + ch_free(li->li_base_path.bv_val); + ldap_pvt_thread_rdwr_destroy(&li->li_rdwr); free( be->be_private ); return 0; } static int -ldif_back_db_open( - Backend *be - ) +ldif_back_db_open( Backend *be, ConfigReply *cr) { - struct ldif_info *ni = (struct ldif_info *) be->be_private; - if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */ + struct ldif_info *li = (struct ldif_info *) be->be_private; + if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */ Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0); return 1; } @@ -1312,7 +1375,6 @@ ldif_back_initialize( bi->bi_tool_sync = 0; bi->bi_tool_dn2id_get = 0; - bi->bi_tool_id2entry_get = 0; bi->bi_tool_entry_modify = 0; bi->bi_cf_ocs = ldifocs; diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index ddd651f7a9..cfa3e73f5a 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -169,8 +169,7 @@ meta_back_add( Operation *op, SlapReply *rs ) retry:; ctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) + if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -184,13 +183,13 @@ retry:; do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); for ( --i; i >= 0; --i ) { free( attrs[ i ]->mod_bvalues ); diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 04d7ba885c..2f7b080e8b 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -31,6 +31,7 @@ /* String rewrite library */ #include "rewrite.h" + LDAP_BEGIN_DECL /* @@ -40,9 +41,6 @@ LDAP_BEGIN_DECL #define META_BACK_PRINT_CONNTREE 0 #endif /* !META_BACK_PRINT_CONNTREE */ -struct slap_conn; -struct slap_op; - /* from back-ldap.h before rwm removal */ struct ldapmap { int drop_missing; @@ -223,7 +221,7 @@ typedef struct metasingleconn_t { } metasingleconn_t; typedef struct metaconn_t { - struct slap_conn *mc_conn; + Connection *mc_conn; #define lc_conn mc_conn unsigned mc_refcnt; @@ -312,6 +310,11 @@ typedef struct metatarget_t { #define META_BACK_TGT_CANCEL_DISCOVER(mt) META_BACK_TGT_ISMASK( (mt), LDAP_BACK_F_CANCEL_MASK2, LDAP_BACK_F_CANCEL_EXOP_DISCOVER ) #define META_BACK_TGT_QUARANTINE(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_QUARANTINE ) +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +#define META_BACK_TGT_ST_REQUEST(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_ST_REQUEST ) +#define META_BACK_TGT_ST_RESPONSE(mt) META_BACK_TGT_ISSET( (mt), LDAP_BACK_F_ST_RESPONSE ) +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + int mt_version; time_t mt_network_timeout; struct timeval mt_bind_timeout; diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index f0297d4a1b..bae5a47782 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -64,7 +64,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) gotit = 0, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; rs->sr_err = LDAP_SUCCESS; @@ -72,24 +72,22 @@ meta_back_bind( Operation *op, SlapReply *rs ) op->o_log_prefix, op->o_req_dn.bv_val, 0 ); /* the test on the bind method should be superfluous */ - if ( op->orb_method == LDAP_AUTH_SIMPLE - && be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) - { - if ( !be_isroot_pw( op ) ) { - rs->sr_err = LDAP_INVALID_CREDENTIALS; - rs->sr_text = NULL; - send_ldap_result( op, rs ); - return rs->sr_err; - } - + switch ( be_rootdn_bind( op, rs ) ) { + case LDAP_SUCCESS: if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; /* frontend will return success */ return rs->sr_err; } isroot = 1; + /* fallthru */ + + case SLAP_CB_CONTINUE: + break; + + default: + /* be_rootdn_bind() sent result */ + return rs->sr_err; } /* we need meta_back_getconn() not send result even on error, @@ -124,6 +122,8 @@ meta_back_bind( Operation *op, SlapReply *rs ) return rs->sr_err; } + candidates = meta_back_candidates_get( op ); + /* * Each target is scanned ... */ @@ -326,6 +326,9 @@ meta_back_bind_op_result( ">>> %s meta_back_bind_op_result[%d]\n", op->o_log_prefix, candidate, 0 ); + /* make sure this is clean */ + assert( rs->sr_ctrls == NULL ); + if ( rs->sr_err == LDAP_SUCCESS ) { time_t stoptime = (time_t)(-1), timeout; @@ -457,6 +460,9 @@ meta_back_single_bind( metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid; dncookie dc; + struct berval save_o_dn; + int save_o_do_not_cache; + LDAPControl **ctrls = NULL; if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); @@ -484,6 +490,20 @@ meta_back_single_bind( return rs->sr_err; } + /* don't add proxyAuthz; set the bindDN */ + save_o_dn = op->o_dn; + save_o_do_not_cache = op->o_do_not_cache; + op->o_do_not_cache = 1; + op->o_dn = op->o_req_dn; + + ctrls = op->o_ctrls; + rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); + op->o_dn = save_o_dn; + op->o_do_not_cache = save_o_do_not_cache; + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + /* FIXME: this fixes the bind problem right now; we need * to use the asynchronous version to get the "matched" * and more in case of failure ... */ @@ -492,12 +512,15 @@ meta_back_single_bind( for (;;) { rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, - op->o_ctrls, NULL, &msgid ); + ctrls, NULL, &msgid ); if ( rs->sr_err != LDAP_X_CONNECTING ) { break; } ldap_pvt_thread_yield(); } + + ldap_back_controls_free( op, rs, &ctrls ); + meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND ); if ( rs->sr_err != LDAP_SUCCESS ) { goto return_results; @@ -636,7 +659,7 @@ meta_back_dobind( i, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; if ( be_isroot( op ) ) { isroot = 1; @@ -656,6 +679,8 @@ meta_back_dobind( goto done; } + candidates = meta_back_candidates_get( op ); + for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; metasingleconn_t *msc = &mc->mc_conns[ i ]; @@ -1018,18 +1043,44 @@ retry:; if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } - if ( refs != NULL ) { - int i; + + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( refs != NULL + && refs[ 0 ] != NULL + && refs[ 0 ][ 0 ] != '\0' ) + { + if ( rs->sr_err != LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got referrals with err=%d\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + } else { + int i; - for ( i = 0; refs[ i ] != NULL; i++ ) - /* count */ ; - rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), - op->o_tmpmemctx ); - for ( i = 0; refs[ i ] != NULL; i++ ) { - ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + for ( i = 0; refs[ i ] != NULL; i++ ) + /* count */ ; + rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), + op->o_tmpmemctx ); + for ( i = 0; refs[ i ] != NULL; i++ ) { + ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + } + BER_BVZERO( &rs->sr_ref[ i ] ); } - BER_BVZERO( &rs->sr_ref[ i ] ); + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } + if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } @@ -1173,9 +1224,11 @@ retry:; ldap_memfree( text ); } if ( rs->sr_ref ) { - assert( refs != NULL ); - ber_memvfree( (void **)refs ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); + rs->sr_ref = NULL; + } + if ( refs ) { + ber_memvfree( (void **)refs ); } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); @@ -1392,6 +1445,14 @@ meta_back_proxy_authz_cred( mt->mt_idassert_authcID.bv_val, mt->mt_idassert_passwd.bv_val, authzID.bv_val ); + if ( defaults == NULL ) { + rs->sr_err = LDAP_OTHER; + LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + goto done; + } rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val, mt->mt_idassert_sasl_mech.bv_val, NULL, NULL, @@ -1496,3 +1557,120 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe return LDAP_BACK_CONN_ISBOUND( msc ); } + +/* + * Add controls; + * + * if any needs to be added, it is prepended to existing ones, + * in a newly allocated array. The companion function + * ldap_back_controls_free() must be used to restore the original + * status of op->o_ctrls. + */ +int +meta_back_controls_add( + Operation *op, + SlapReply *rs, + metaconn_t *mc, + int candidate, + LDAPControl ***pctrls ) +{ + metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; + metatarget_t *mt = mi->mi_targets[ candidate ]; + metasingleconn_t *msc = &mc->mc_conns[ candidate ]; + + LDAPControl **ctrls = NULL; + /* set to the maximum number of controls this backend can add */ + LDAPControl c[ 2 ] = { 0 }; + int i = 0, j = 0; + + *pctrls = NULL; + + rs->sr_err = LDAP_SUCCESS; + + /* don't add controls if protocol is not LDAPv3 */ + switch ( mt->mt_version ) { + case LDAP_VERSION3: + break; + + case 0: + if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { + break; + } + /* fall thru */ + + default: + goto done; + } + + /* proxyAuthz for identity assertion */ + switch ( ldap_back_proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, + mt->mt_version, &mt->mt_idassert, &c[ j ] ) ) + { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j++; + break; + + default: + goto done; + } + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + /* session tracking */ + if ( META_BACK_TGT_ST_REQUEST( mt ) ) { + switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j ] ) ) { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j++; + break; + + default: + goto done; + } + } +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + + if ( rs->sr_err == SLAP_CB_CONTINUE ) { + rs->sr_err = LDAP_SUCCESS; + } + + if ( j == 0 ) { + goto done; + } + + if ( op->o_ctrls ) { + for ( i = 0; op->o_ctrls[ i ]; i++ ) + /* just count ctrls */ ; + } + + ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + j + 1) + j * sizeof( LDAPControl ), + op->o_tmpmemctx ); + ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + j + 1 ]; + *ctrls[ 0 ] = c[ 0 ]; + for ( i = 1; i < j; i++ ) { + ctrls[ i ] = &ctrls[ 0 ][ i ]; + *ctrls[ i ] = c[ i ]; + } + + i = 0; + if ( op->o_ctrls ) { + for ( i = 0; op->o_ctrls[ i ]; i++ ) { + ctrls[ i + j ] = op->o_ctrls[ i ]; + } + } + ctrls[ i + j ] = NULL; + +done:; + if ( ctrls == NULL ) { + ctrls = op->o_ctrls; + } + + *pctrls = ctrls; + + return rs->sr_err; +} + diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index 0a8cf10e6b..b381daf89e 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -113,8 +113,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) retry:; ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ); + rc = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -130,13 +129,13 @@ retry:; do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index d90e40ec25..92947b8bec 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -111,13 +111,11 @@ meta_back_db_config( /* URI of server to query */ if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) { int i = mi->mi_ntargets; -#if 0 - int j; -#endif /* uncomment if uri MUST be a branch of suffix */ LDAPURLDesc *ludp, *tmpludp; struct berval dn; int rc; int c; + BackendDB *tmp_bd; metatarget_t *mt; @@ -282,26 +280,14 @@ meta_back_db_config( /* * uri MUST be a branch of suffix! */ -#if 0 /* too strict a constraint */ - if ( select_backend( &mt->mt_nsuffix, 0, 0 ) != be ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: of URI does not refer to current backend" - " in \"uri ://[:port]/\" line\n", - fname, lineno, 0 ); - return 1; - } -#else - /* - * uri MUST be a branch of a suffix! - */ - if ( select_backend( &mt->mt_nsuffix, 0, 0 ) == NULL ) { + tmp_bd = select_backend( &mt->mt_nsuffix, 0 ); + if ( tmp_bd == NULL || tmp_bd->be_private != be->be_private ) + { Debug( LDAP_DEBUG_ANY, - "%s: line %d: of URI does not resolve to a backend" - " in \"uri ://[:port]/\" line\n", + "%s: line %d: of URI does not resolve to this database.\n", fname, lineno, 0 ); return 1; } -#endif /* subtree-exclude */ } else if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 ) { @@ -1235,10 +1221,42 @@ idassert-authzFrom "dn:" } else { mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags |= LDAP_BACK_F_QUARANTINE; } + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + /* session tracking request */ + } else if ( strcasecmp( argv[ 0 ], "session-tracking-request" ) == 0 ) { + unsigned *flagsp = mi->mi_ntargets ? + &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags + : &mi->mi_flags; + + if ( argc != 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: \"session-tracking-request {TRUE|false}\" needs 1 argument.\n", + fname, lineno, 0 ); + return( 1 ); + } + + /* this is the default; we add it because the default might change... */ + switch ( check_true_false( argv[ 1 ] ) ) { + case 1: + *flagsp |= LDAP_BACK_F_ST_REQUEST; + break; + + case 0: + *flagsp &= ~LDAP_BACK_F_ST_REQUEST; + break; + + default: + Debug( LDAP_DEBUG_ANY, + "%s: line %d: \"session-tracking-request {TRUE|false}\": unknown argument \"%s\".\n", + fname, lineno, argv[ 1 ] ); + return( 1 ); + } +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ /* dn massaging */ } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) { - BackendDB *tmp_be; + BackendDB *tmp_bd; int i = mi->mi_ntargets - 1, rc; struct berval dn, nvnc, pvnc, nrnc, prnc; @@ -1270,17 +1288,17 @@ idassert-authzFrom "dn:" ber_str2bv( argv[ 1 ], 0, 0, &dn ); if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "suffix '%s' is invalid\n", + "suffix \"%s\" is invalid\n", fname, lineno, argv[ 1 ] ); return 1; } - tmp_be = select_backend( &nvnc, 0, 0 ); - if ( tmp_be != NULL && tmp_be != be ) { + tmp_bd = select_backend( &nvnc, 0 ); + if ( tmp_bd != NULL && tmp_bd->be_private != be->be_private ) { Debug( LDAP_DEBUG_ANY, - "%s: line %d: suffix already in use by another backend in" - " \"suffixMassage \"\n", - fname, lineno, 0 ); + "%s: line %d: \"%s\" already in use by another database, in " + "\"suffixMassage \"\n", + fname, lineno, pvnc.bv_val ); free( pvnc.bv_val ); free( nvnc.bv_val ); return 1; @@ -1289,33 +1307,27 @@ idassert-authzFrom "dn:" ber_str2bv( argv[ 2 ], 0, 0, &dn ); if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "massaged suffix '%s' is invalid\n", + "massaged suffix \"%s\" is invalid\n", fname, lineno, argv[ 2 ] ); free( pvnc.bv_val ); free( nvnc.bv_val ); return 1; } -#if 0 - tmp_be = select_backend( &nrnc, 0, 0 ); - if ( tmp_be != NULL ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: massaged suffix already in use by another backend in" - " \"suffixMassage \"\n", - fname, lineno, 0 ); + tmp_bd = select_backend( &nrnc, 0 ); + if ( tmp_bd != NULL && tmp_bd->be_private == be->be_private ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: warning: \"%s\" point to this database, in " + "\"suffixMassage \"\n", + fname, lineno, prnc.bv_val ); free( pvnc.bv_val ); free( nvnc.bv_val ); - free( prnc.bv_val ); - free( nrnc.bv_val ); - return 1; + return 1; } -#endif - + /* * The suffix massaging is emulated by means of the * rewrite capabilities - * FIXME: no extra rewrite capabilities should be added - * to the database */ rc = suffix_massage_config( mi->mi_targets[ i ]->mt_rwmap.rwm_rw, &pvnc, &nvnc, &prnc, &nrnc ); diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index 8f1eaac21b..da4d7553cd 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -67,8 +67,7 @@ meta_back_delete( Operation *op, SlapReply *rs ) retry:; ctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) + if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -82,13 +81,13 @@ retry:; do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 89f27ad818..a530d7cd89 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -23,6 +23,7 @@ #include #include "slap.h" +#include "config.h" #include "../back-ldap/back-ldap.h" #include "back-meta.h" @@ -87,7 +88,8 @@ meta_back_initialize( int meta_back_db_init( - Backend *be ) + Backend *be, + ConfigReply *cr) { metainfo_t *mi; int i; @@ -128,7 +130,8 @@ meta_back_db_init( int meta_back_db_open( - Backend *be ) + Backend *be, + ConfigReply *cr ) { metainfo_t *mi = (metainfo_t *)be->be_private; @@ -328,7 +331,8 @@ target_free( int meta_back_db_destroy( - Backend *be ) + Backend *be, + ConfigReply *cr ) { metainfo_t *mi; diff --git a/servers/slapd/back-meta/map.c b/servers/slapd/back-meta/map.c index 4d6aa59b61..1871ebbddf 100644 --- a/servers/slapd/back-meta/map.c +++ b/servers/slapd/back-meta/map.c @@ -326,7 +326,7 @@ ldap_back_int_filter_map_rewrite( fstr->bv_val = malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", - atmp.bv_val, vtmp.bv_val ); + atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); break; @@ -343,7 +343,7 @@ ldap_back_int_filter_map_rewrite( fstr->bv_val = malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", - atmp.bv_val, vtmp.bv_val ); + atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); break; @@ -360,7 +360,7 @@ ldap_back_int_filter_map_rewrite( fstr->bv_val = malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", - atmp.bv_val, vtmp.bv_val ); + atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); break; @@ -377,7 +377,7 @@ ldap_back_int_filter_map_rewrite( fstr->bv_val = malloc( fstr->bv_len + 1 ); snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", - atmp.bv_val, vtmp.bv_val ); + atmp.bv_val, vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); break; @@ -407,7 +407,7 @@ ldap_back_int_filter_map_rewrite( snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3, /* "(attr=" */ "%s*)", - vtmp.bv_val ); + vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); } @@ -422,7 +422,7 @@ ldap_back_int_filter_map_rewrite( snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, /* "(attr=[init]*[any*]" */ "%s*)", - vtmp.bv_val ); + vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); } } @@ -437,7 +437,7 @@ ldap_back_int_filter_map_rewrite( snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, /* "(attr=[init*][any*]" */ "%s)", - vtmp.bv_val ); + vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); } @@ -482,7 +482,7 @@ ldap_back_int_filter_map_rewrite( fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, - /*"("*/ "%s)", vtmp.bv_val ); + /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" ); ch_free( vtmp.bv_val ); } @@ -514,7 +514,7 @@ ldap_back_int_filter_map_rewrite( f->f_mr_dnattrs ? ":dn" : "", !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "", !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "", - vtmp.bv_val ); + vtmp.bv_len ? vtmp.bv_val : "" ); ber_memfree( vtmp.bv_val ); break; diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index a1088c7932..ef117860e0 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -178,8 +178,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) retry:; ctrls = op->o_ctrls; - rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ); + rc = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -193,13 +192,13 @@ retry:; do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index 2a14b27208..66222cfefd 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -120,8 +120,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) retry:; ctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) + if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -137,13 +136,13 @@ retry:; do_retry = 0; if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } } cleanup:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( mdn.bv_val != op->o_req_dn.bv_val ) { free( mdn.bv_val ); diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index ba163e9f09..c9e435b41d 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -232,10 +232,10 @@ meta_search_dobind_init( assert( msc->msc_ld != NULL ); - /* connect must be async */ -retry:; + /* connect must be async only the first time... */ ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON ); +retry:; rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &candidates[ candidate ].sr_msgid ); @@ -316,6 +316,7 @@ down:; if ( *mcp == NULL ) { retcode = META_SEARCH_ERR; rs->sr_err = LDAP_UNAVAILABLE; + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; break; } /* fall thru */ @@ -597,8 +598,7 @@ meta_back_search_start( retry:; ctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &msc->msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) + if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; @@ -624,12 +624,13 @@ retry:; if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) { nretries = 0; /* if the identity changed, there might be need to re-authz */ - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); goto retry; } if ( *mcp == NULL ) { retcode = META_SEARCH_ERR; + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; break; } /* fall thru */ @@ -640,7 +641,7 @@ retry:; } done:; - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + (void)ldap_back_controls_free( op, rs, &ctrls ); if ( mapped_attrs ) { free( mapped_attrs ); @@ -678,7 +679,7 @@ meta_back_search( Operation *op, SlapReply *rs ) dncookie dc; int is_ok = 0; void *savepriv; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates = NULL; /* * controls are set in ldap_back_dobind() @@ -695,6 +696,7 @@ getconn:; dc.conn = op->o_conn; dc.rs = rs; + if ( candidates == NULL ) candidates = meta_back_candidates_get( op ); /* * Inits searches */ @@ -870,7 +872,6 @@ getconn:; int gotit = 0, doabandon = 0, alreadybound = ncandidates; - time_t curr_time = 0; /* check timeout */ if ( timeout && lastres_time > 0 @@ -1223,6 +1224,8 @@ really_bad:; candidates[ i ].sr_type = REP_RESULT; } + candidates[ i ].sr_msgid = META_MSGID_IGNORE; + /* NOTE: ignores response controls * (and intermediate response controls * as well, except for those with search @@ -1241,16 +1244,15 @@ really_bad:; NULL /* &candidates[ i ].sr_ctrls (unused) */ , 0 ); if ( rs->sr_err != LDAP_SUCCESS ) { - ldap_get_option( msc->msc_ld, - LDAP_OPT_ERROR_NUMBER, - &rs->sr_err ); - sres = slap_map_api2result( rs ); + sres = slap_map_api2result( &candidates[ i ] ); candidates[ i ].sr_type = REP_RESULT; ldap_msgfree( res ); res = NULL; goto really_bad; } + rs->sr_err = candidates[ i ].sr_err; + /* massage matchedDN if need be */ if ( candidates[ i ].sr_matched != NULL ) { struct berval match, mmatch; @@ -1276,37 +1278,60 @@ really_bad:; } /* add references to array */ - if ( references ) { - BerVarray sr_ref; - int cnt; + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( references != NULL + && references[ 0 ] != NULL + && references[ 0 ][ 0 ] != '\0' ) + { + if ( rs->sr_err != LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_search[%ld]: " + "got referrals with err=%d\n", + op->o_log_prefix, + i, rs->sr_err ); + + } else { + BerVarray sr_ref; + int cnt; - for ( cnt = 0; references[ cnt ]; cnt++ ) - ; + for ( cnt = 0; references[ cnt ]; cnt++ ) + ; - sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 ); + sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 ); - for ( cnt = 0; references[ cnt ]; cnt++ ) { - ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] ); - } - BER_BVZERO( &sr_ref[ cnt ] ); + for ( cnt = 0; references[ cnt ]; cnt++ ) { + ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] ); + } + BER_BVZERO( &sr_ref[ cnt ] ); - ( void )ldap_back_referral_result_rewrite( &dc, sr_ref ); + ( void )ldap_back_referral_result_rewrite( &dc, sr_ref ); - /* cleanup */ - ber_memvfree( (void **)references ); - - if ( rs->sr_v2ref == NULL ) { - rs->sr_v2ref = sr_ref; + if ( rs->sr_v2ref == NULL ) { + rs->sr_v2ref = sr_ref; - } else { - for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) { - ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] ); + } else { + for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) { + ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] ); + } + ber_memfree( sr_ref ); } - ber_memfree( sr_ref ); } + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_search[%ld]: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + i, rs->sr_err ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } + + /* cleanup */ + ber_memvfree( (void **)references ); - rs->sr_err = candidates[ i ].sr_err; sres = slap_map_api2result( rs ); if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) { @@ -1387,7 +1412,6 @@ really_bad:; * When no candidates are left, * the outer cycle finishes */ - candidates[ i ].sr_msgid = META_MSGID_IGNORE; assert( ncandidates > 0 ); --ncandidates; @@ -1444,10 +1468,16 @@ free_message:; /* check for abandon */ if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) { for ( i = 0; i < mi->mi_ntargets; i++ ) { - if ( candidates[ i ].sr_msgid >= 0 ) { - if ( META_IS_BINDING( &candidates[ i ] ) ) { + if ( candidates[ i ].sr_msgid >= 0 + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) + { + if ( META_IS_BINDING( &candidates[ i ] ) + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) + { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { + if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) + { /* if still binding, destroy */ #ifdef DEBUG_205 @@ -1644,23 +1674,35 @@ finish:; continue; } - if ( mc && META_IS_BINDING( &candidates[ i ] ) ) { - ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { - assert( candidates[ i ].sr_msgid >= 0 ); - assert( mc->mc_conns[ i ].msc_ld != NULL ); + if ( mc ) { + if ( META_IS_BINDING( &candidates[ i ] ) + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) + { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ) + { + assert( candidates[ i ].sr_msgid >= 0 + || candidates[ i ].sr_msgid == META_MSGID_CONNECTING ); + assert( mc->mc_conns[ i ].msc_ld != NULL ); #ifdef DEBUG_205 - Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) " - "ldap_unbind_ext[%ld] ld=%p\n", - op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); + Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) " + "ldap_unbind_ext[%ld] ld=%p\n", + op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); #endif /* DEBUG_205 */ - /* if still binding, destroy */ - meta_clear_one_candidate( op, mc, i ); + /* if still binding, destroy */ + meta_clear_one_candidate( op, mc, i ); + } + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + META_BINDING_CLEAR( &candidates[ i ] ); + + } else if ( candidates[ i ].sr_msgid >= 0 ) { + (void)meta_back_cancel( mc, op, rs, + candidates[ i ].sr_msgid, i, + LDAP_BACK_DONTSEND ); } - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - META_BINDING_CLEAR( &candidates[ i ] ); } if ( candidates[ i ].sr_matched ) { @@ -1718,6 +1760,7 @@ meta_send_entry( { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; struct berval a, mapped; + int check_duplicate_attrs = 0; Entry ent = { 0 }; BerElement ber = *e->lm_ber; Attribute *attr, **attrp; @@ -1784,6 +1827,10 @@ meta_send_entry( ( void )ber_scanf( &ber, "x" /* [W] */ ); continue; } + if ( mapped.bv_val != a.bv_val ) { + /* will need to check for duplicate attrs */ + check_duplicate_attrs++; + } attr = attr_alloc( NULL ); if ( attr == NULL ) { continue; @@ -1856,6 +1903,7 @@ meta_send_entry( ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc, bv, &mapped, BACKLDAP_REMAP ); if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') { +remove_oc:; free( bv->bv_val ); BER_BVZERO( bv ); if ( --last < 0 ) { @@ -1866,8 +1914,23 @@ meta_send_entry( bv--; } else if ( mapped.bv_val != bv->bv_val ) { - free( bv->bv_val ); - ber_dupbv( bv, &mapped ); + int i; + + for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) { + if ( &attr->a_vals[ i ] == bv ) { + continue; + } + + if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) { + break; + } + } + + if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) { + goto remove_oc; + } + + ber_bvreplace( bv, &mapped ); } } /* @@ -1955,8 +2018,53 @@ meta_send_entry( attrp = &attr->a_next; next_attr:; } + + /* only check if some mapping occurred */ + if ( check_duplicate_attrs ) { + Attribute **ap; + + for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) { + Attribute **tap; + + for ( tap = &(*ap)->a_next; *tap != NULL; ) { + if ( (*tap)->a_desc == (*ap)->a_desc ) { + Entry e = { 0 }; + Modification mod = { 0 }; + const char *text = NULL; + char textbuf[ SLAP_TEXT_BUFLEN ]; + Attribute *next = (*tap)->a_next; + + BER_BVSTR( &e.e_name, "" ); + BER_BVSTR( &e.e_nname, "" ); + e.e_attrs = *ap; + mod.sm_op = LDAP_MOD_ADD; + mod.sm_desc = (*ap)->a_desc; + mod.sm_type = mod.sm_desc->ad_cname; + mod.sm_values = (*tap)->a_vals; + mod.sm_nvalues = (*tap)->a_nvals; + + (void)modify_add_values( &e, &mod, + /* permissive */ 1, + &text, textbuf, sizeof( textbuf ) ); + + /* should not insert new attrs! */ + assert( e.e_attrs == *ap ); + + attr_free( *tap ); + *tap = next; + + } else { + tap = &(*tap)->a_next; + } + } + } + } + + ldap_get_entry_controls( mc->mc_conns[target].msc_ld, + e, &rs->sr_ctrls ); rs->sr_entry = &ent; rs->sr_attrs = op->ors_attrs; + rs->sr_operational_attrs = NULL; rs->sr_flags = 0; rs->sr_err = LDAP_SUCCESS; rc = send_search_entry( op, rs ); @@ -1967,7 +2075,10 @@ next_attr:; } rs->sr_entry = NULL; rs->sr_attrs = NULL; - + if ( rs->sr_ctrls != NULL ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } if ( !BER_BVISNULL( &ent.e_name ) ) { free( ent.e_name.bv_val ); BER_BVZERO( &ent.e_name ); diff --git a/servers/slapd/back-monitor/back-monitor.h b/servers/slapd/back-monitor/back-monitor.h index 79bf085872..6e1ad91793 100644 --- a/servers/slapd/back-monitor/back-monitor.h +++ b/servers/slapd/back-monitor/back-monitor.h @@ -74,6 +74,8 @@ typedef struct monitor_entry_t { struct monitor_callback_t *mp_cb; /* callback sequence */ } monitor_entry_t; +struct entry_limbo_t; /* in init.c */ + typedef struct monitor_info_t { /* @@ -135,7 +137,7 @@ typedef struct monitor_info_t { AttributeDescription *mi_ad_readOnly; AttributeDescription *mi_ad_restrictedOperation; - void *mi_entry_limbo; + struct entry_limbo_t *mi_entry_limbo; } monitor_info_t; /* @@ -285,6 +287,10 @@ typedef struct monitor_extra_t { monitor_subsys_t * (*get_subsys_by_dn)( struct berval *ndn, int sub ); int (*register_subsys)( monitor_subsys_t *ms ); + int (*register_backend)( BackendInfo *bi ); + int (*register_database)( BackendDB *be ); + int (*register_overlay_info)( slap_overinst *on ); + int (*register_overlay)( BackendDB *be ); int (*register_entry)( Entry *e, monitor_callback_t *cb, monitor_subsys_t *ms, unsigned long flags ); int (*register_entry_parent)( Entry *e, monitor_callback_t *cb, diff --git a/servers/slapd/back-monitor/bind.c b/servers/slapd/back-monitor/bind.c index bc7dbc5298..984253479b 100644 --- a/servers/slapd/back-monitor/bind.c +++ b/servers/slapd/back-monitor/bind.c @@ -35,11 +35,8 @@ monitor_back_bind( Operation *op, SlapReply *rs ) { Debug(LDAP_DEBUG_ARGS, "==> monitor_back_bind: dn: %s\n", op->o_req_dn.bv_val, 0, 0 ); - - if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE - && be_isroot_pw( op ) ) - { - ber_dupbv( &op->oq_bind.rb_edn, be_root_dn( op->o_bd ) ); + + if ( be_isroot_pw( op ) ) { return LDAP_SUCCESS; } diff --git a/servers/slapd/back-monitor/compare.c b/servers/slapd/back-monitor/compare.c index 09eb118d23..3a8df66624 100644 --- a/servers/slapd/back-monitor/compare.c +++ b/servers/slapd/back-monitor/compare.c @@ -27,7 +27,7 @@ #include "back-monitor.h" int -monitor_back_compare( struct slap_op *op, struct slap_rep *rs) +monitor_back_compare( Operation *op, SlapReply *rs ) { monitor_info_t *mi = ( monitor_info_t * ) op->o_bd->be_private; Entry *e, *matched = NULL; diff --git a/servers/slapd/back-monitor/database.c b/servers/slapd/back-monitor/database.c index 2ae676a0c9..f09001ed2b 100644 --- a/servers/slapd/back-monitor/database.c +++ b/servers/slapd/back-monitor/database.c @@ -341,6 +341,112 @@ monitor_subsys_database_init_one( return 0; } +int +monitor_back_register_database( + BackendDB *be ) +{ + monitor_info_t *mi; + Entry *e_database, **ep; + int i, rc; + monitor_entry_t *mp; + monitor_subsys_t *ms_backend, + *ms_database, + *ms_overlay; + struct berval bv; + char buf[ BACKMONITOR_BUFSIZE ]; + + assert( be_monitor != NULL ); + + if ( !monitor_subsys_is_opened() ) { + return monitor_back_register_database_limbo( be ); + } + + mi = ( monitor_info_t * )be_monitor->be_private; + + ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME ); + if ( ms_backend == NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_back_register_database: " + "unable to get " + "\"" SLAPD_MONITOR_BACKEND_NAME "\" " + "subsystem\n", + 0, 0, 0 ); + return -1; + } + + ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME ); + if ( ms_database == NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_back_register_database: " + "unable to get " + "\"" SLAPD_MONITOR_DATABASE_NAME "\" " + "subsystem\n", + 0, 0, 0 ); + return -1; + } + + ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME ); + if ( ms_overlay == NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_back_register_database: " + "unable to get " + "\"" SLAPD_MONITOR_OVERLAY_NAME "\" " + "subsystem\n", + 0, 0, 0 ); + return -1; + } + + if ( monitor_cache_get( mi, &ms_database->mss_ndn, &e_database ) ) { + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_database_init: " + "unable to get entry \"%s\"\n", + ms_database->mss_ndn.bv_val, 0, 0 ); + return( -1 ); + } + + mp = ( monitor_entry_t * )e_database->e_private; + for ( i = -1, ep = &mp->mp_children; *ep; i++ ) { + Attribute *a; + + a = attr_find( (*ep)->e_attrs, slap_schema.si_ad_namingContexts ); + if ( a ) { + int j, k; + + for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) { + for ( k = 0; !BER_BVISNULL( &be->be_nsuffix[ k ] ); k++ ) { + if ( dn_match( &a->a_nvals[ j ], &be->be_nsuffix[ k ] ) ) { + rc = 0; + goto done; + } + } + } + } + + mp = ( monitor_entry_t * )(*ep)->e_private; + + assert( mp != NULL ); + ep = &mp->mp_next; + } + + bv.bv_val = buf; + bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", i ); + if ( bv.bv_len >= sizeof( buf ) ) { + rc = -1; + goto done; + } + + rc = monitor_subsys_database_init_one( mi, be, + ms_database, ms_backend, ms_overlay, &bv, e_database, &ep ); + if ( rc != 0 ) { + goto done; + } + +done:; + monitor_cache_release( mi, e_database ); + + return rc; +} + int monitor_subsys_database_init( BackendDB *be, diff --git a/servers/slapd/back-monitor/init.c b/servers/slapd/back-monitor/init.c index 978d1301c8..3df03cba3a 100644 --- a/servers/slapd/back-monitor/init.c +++ b/servers/slapd/back-monitor/init.c @@ -52,6 +52,10 @@ static const monitor_extra_t monitor_extra = { monitor_back_get_subsys_by_dn, monitor_back_register_subsys, + monitor_back_register_backend, + monitor_back_register_database, + monitor_back_register_overlay_info, + monitor_back_register_overlay, monitor_back_register_entry, monitor_back_register_entry_parent, monitor_back_register_entry_attrs, @@ -221,6 +225,12 @@ static struct monitor_subsys_t known_monitor_subsys[] = { }, { NULL } }; +int +monitor_subsys_is_opened( void ) +{ + return monitor_subsys_opened; +} + int monitor_back_register_subsys( monitor_subsys_t *ms ) @@ -245,7 +255,7 @@ monitor_back_register_subsys( /* if a subsystem is registered __AFTER__ subsystem * initialization (depending on the sequence the databases * are listed in slapd.conf), init it */ - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { /* FIXME: this should only be possible * if be_monitor is already initialized */ @@ -265,11 +275,20 @@ enum { LIMBO_ENTRY, LIMBO_ENTRY_PARENT, LIMBO_ATTRS, - LIMBO_CB + LIMBO_CB, + LIMBO_BACKEND, + LIMBO_DATABASE, + LIMBO_OVERLAY_INFO, + LIMBO_OVERLAY, + + LIMBO_LAST }; typedef struct entry_limbo_t { int el_type; + BackendInfo *el_bi; + BackendDB *el_be; + slap_overinst *el_on; Entry *el_e; Attribute *el_a; struct berval el_ndn; @@ -288,6 +307,83 @@ monitor_back_is_configured( void ) return be_monitor != NULL; } +int +monitor_back_register_backend( + BackendInfo *bi ) +{ + return -1; +} + +int +monitor_back_register_overlay_info( + slap_overinst *on ) +{ + return -1; +} + +int +monitor_back_register_overlay( + BackendDB *be ) +{ + return -1; +} + +int +monitor_back_register_backend_limbo( + BackendInfo *bi ) +{ + return -1; +} + +int +monitor_back_register_database_limbo( + BackendDB *be ) +{ + entry_limbo_t **elpp, el = { 0 }; + monitor_info_t *mi; + + if ( be_monitor == NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_back_register_database_limbo: " + "monitor database not configured.\n", + 0, 0, 0 ); + return -1; + } + + mi = ( monitor_info_t * )be_monitor->be_private; + + + el.el_type = LIMBO_DATABASE; + + el.el_be = be; + + for ( elpp = &mi->mi_entry_limbo; + *elpp; + elpp = &(*elpp)->el_next ) + /* go to last */; + + *elpp = (entry_limbo_t *)ch_malloc( sizeof( entry_limbo_t ) ); + + el.el_next = NULL; + **elpp = el; + + return 0; +} + +int +monitor_back_register_overlay_info_limbo( + slap_overinst *on ) +{ + return -1; +} + +int +monitor_back_register_overlay_limbo( + BackendDB *be ) +{ + return -1; +} + int monitor_back_register_entry( Entry *e, @@ -311,7 +407,7 @@ monitor_back_register_entry( assert( e != NULL ); assert( e->e_private == NULL ); - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e_parent = NULL, *e_new = NULL, **ep = NULL; @@ -433,7 +529,7 @@ done:; el.el_mss = mss; el.el_flags = flags; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) /* go to last */; @@ -490,7 +586,7 @@ monitor_back_register_entry_parent( return -1; } - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e_parent = NULL, *e_new = NULL, **ep = NULL; @@ -647,7 +743,7 @@ done:; el.el_mss = mss; el.el_flags = flags; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) /* go to last */; @@ -717,9 +813,9 @@ monitor_search2ndn( return -1; } - op = (Operation *) &opbuf; thrctx = ldap_pvt_thread_pool_context(); - connection_fake_init( &conn, op, thrctx ); + connection_fake_init( &conn, &opbuf, thrctx ); + op = &opbuf.ob_op; op->o_tag = LDAP_REQ_SEARCH; @@ -858,7 +954,7 @@ monitor_back_register_entry_attrs( return -1; } - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e = NULL; Attribute **atp = NULL; monitor_entry_t *mp = NULL; @@ -980,7 +1076,7 @@ done:; el.el_a = attrs_dup( a ); el.el_cb = cb; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) /* go to last */; @@ -1058,7 +1154,7 @@ monitor_back_unregister_entry( assert( mi != NULL ); - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e = NULL; monitor_entry_t *mp = NULL; monitor_callback_t *cb = NULL; @@ -1093,7 +1189,7 @@ monitor_back_unregister_entry( } else { entry_limbo_t **elpp; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) { @@ -1107,6 +1203,9 @@ monitor_back_unregister_entry( for ( cb = elp->el_cb; cb; cb = next ) { /* FIXME: call callbacks? */ next = cb->mc_next; + if ( cb->mc_dispose ) { + cb->mc_dispose( &cb->mc_private ); + } ch_free( cb ); } assert( elp->el_e != NULL ); @@ -1171,7 +1270,7 @@ monitor_back_unregister_entry_parent( return -1; } - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e = NULL; monitor_entry_t *mp = NULL; @@ -1224,7 +1323,7 @@ monitor_back_unregister_entry_parent( } else { entry_limbo_t **elpp; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) { @@ -1241,6 +1340,9 @@ monitor_back_unregister_entry_parent( for ( cb = elp->el_cb; cb; cb = next ) { /* FIXME: call callbacks? */ next = cb->mc_next; + if ( cb->mc_dispose ) { + cb->mc_dispose( &cb->mc_private ); + } ch_free( cb ); } assert( elp->el_e != NULL ); @@ -1326,7 +1428,7 @@ monitor_back_unregister_entry_attrs( return -1; } - if ( monitor_subsys_opened ) { + if ( monitor_subsys_is_opened() ) { Entry *e = NULL; monitor_entry_t *mp = NULL; int freeit = 0; @@ -1400,14 +1502,12 @@ monitor_back_unregister_entry_attrs( ber_memfree( ndn.bv_val ); } - if ( e ) { - monitor_cache_release( mi, e ); - } + monitor_cache_release( mi, e ); } else { entry_limbo_t **elpp; - for ( elpp = (entry_limbo_t **)&mi->mi_entry_limbo; + for ( elpp = &mi->mi_entry_limbo; *elpp; elpp = &(*elpp)->el_next ) { @@ -1423,6 +1523,9 @@ monitor_back_unregister_entry_attrs( for ( cb = elp->el_cb; cb; cb = next ) { /* FIXME: call callbacks? */ next = cb->mc_next; + if ( cb->mc_dispose ) { + cb->mc_dispose( &cb->mc_private ); + } ch_free( cb ); } assert( elp->el_e == NULL ); @@ -1933,7 +2036,6 @@ monitor_back_initialize( bi->bi_tool_entry_reindex = 0; bi->bi_tool_sync = 0; bi->bi_tool_dn2id_get = 0; - bi->bi_tool_id2entry_get = 0; bi->bi_tool_entry_modify = 0; bi->bi_connection_init = 0; @@ -1956,7 +2058,8 @@ monitor_back_initialize( int monitor_back_db_init( - BackendDB *be ) + BackendDB *be, + ConfigReply *c) { int rc; struct berval dn = BER_BVC( SLAPD_MONITOR_DN ), @@ -1967,23 +2070,24 @@ monitor_back_db_init( monitor_subsys_t *ms; /* - * register subsys + * database monitor can be defined once only */ - for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) { - if ( monitor_back_register_subsys( ms ) ) { - return -1; + if ( be_monitor != NULL ) { + if (c) { + snprintf(c->msg, sizeof(c->msg),"only one monitor database allowed"); } + return( -1 ); } + be_monitor = be; /* - * database monitor can be defined once only + * register subsys */ - if ( be_monitor != NULL ) { - Debug( LDAP_DEBUG_ANY, - "only one monitor database is allowed\n", 0, 0, 0 ); - return( -1 ); + for ( ms = known_monitor_subsys; ms->mss_name != NULL; ms++ ) { + if ( monitor_back_register_subsys( ms ) ) { + return -1; + } } - be_monitor = be; /* indicate system schema supported */ SLAP_BFLAGS(be) |= SLAP_BFLAG_MONITOR; @@ -2005,7 +2109,7 @@ monitor_back_db_init( be->be_private = &monitor_info; - be2 = select_backend( &ndn, 0, 0 ); + be2 = select_backend( &ndn, 0 ); if ( be2 != be ) { char *type = be2->bd_info->bi_type; @@ -2014,19 +2118,60 @@ monitor_back_db_init( type = oi->oi_orig->bi_type; } - Debug( LDAP_DEBUG_ANY, - "\"monitor\" database serving namingContext \"%s\" " - "is hidden by \"%s\" database serving namingContext \"%s\".\n", - pdn.bv_val, type, be2->be_nsuffix[ 0 ].bv_val ); + if (c) { + snprintf(c->msg, sizeof(c->msg), + "\"monitor\" database serving namingContext \"%s\" " + "is hidden by \"%s\" database serving namingContext \"%s\".\n", + pdn.bv_val, type, be2->be_nsuffix[ 0 ].bv_val ); + } return -1; } return 0; } +static void +monitor_back_destroy_limbo_entry( + entry_limbo_t *el, + int dispose ) +{ + if ( el->el_e ) { + entry_free( el->el_e ); + } + if ( el->el_a ) { + attrs_free( el->el_a ); + } + if ( !BER_BVISNULL( &el->el_ndn ) ) { + ber_memfree( el->el_ndn.bv_val ); + } + if ( !BER_BVISNULL( &el->el_nbase ) ) { + ber_memfree( el->el_nbase.bv_val ); + } + if ( !BER_BVISNULL( &el->el_filter ) ) { + ber_memfree( el->el_filter.bv_val ); + } + + /* NOTE: callbacks are not copied; so only free them + * if disposing of */ + if ( el->el_cb && dispose != 0 ) { + monitor_callback_t *next; + + for ( ; el->el_cb; el->el_cb = next ) { + next = el->el_cb->mc_next; + if ( el->el_cb->mc_dispose ) { + el->el_cb->mc_dispose( &el->el_cb->mc_private ); + } + ch_free( el->el_cb ); + } + } + + ch_free( el ); +} + int monitor_back_db_open( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr) { monitor_info_t *mi = (monitor_info_t *)be->be_private; struct monitor_subsys_t **ms; @@ -2046,6 +2191,8 @@ monitor_back_db_open( " attributes, which must be explicitly requested."), BER_BVNULL }; + int retcode = 0; + assert( be_monitor != NULL ); if ( be != be_monitor ) { be_monitor = be; @@ -2225,7 +2372,7 @@ monitor_back_db_open( monitor_subsys_opened = 1; if ( mi->mi_entry_limbo ) { - entry_limbo_t *el = (entry_limbo_t *)mi->mi_entry_limbo; + entry_limbo_t *el = mi->mi_entry_limbo; for ( ; el; ) { entry_limbo_t *tmp; @@ -2271,41 +2418,40 @@ monitor_back_db_open( &el->el_filter ); break; + case LIMBO_BACKEND: + rc = monitor_back_register_backend( el->el_bi ); + break; + + case LIMBO_DATABASE: + rc = monitor_back_register_database( el->el_be ); + break; + + case LIMBO_OVERLAY_INFO: + rc = monitor_back_register_overlay_info( el->el_on ); + break; + + case LIMBO_OVERLAY: + rc = monitor_back_register_overlay( el->el_be ); + break; + default: assert( 0 ); } - if ( el->el_e ) { - entry_free( el->el_e ); - } - if ( el->el_a ) { - attrs_free( el->el_a ); - } - if ( !BER_BVISNULL( &el->el_ndn ) ) { - ber_memfree( el->el_ndn.bv_val ); - } - if ( !BER_BVISNULL( &el->el_nbase ) ) { - ber_memfree( el->el_nbase.bv_val ); - } - if ( !BER_BVISNULL( &el->el_filter ) ) { - ber_memfree( el->el_filter.bv_val ); - } - if ( el->el_cb && rc != 0 ) { - if ( el->el_cb->mc_dispose ) { - el->el_cb->mc_dispose( &el->el_cb->mc_private ); - } - ch_free( el->el_cb ); - } - tmp = el; el = el->el_next; - ch_free( tmp ); + monitor_back_destroy_limbo_entry( tmp, rc ); + + if ( rc != 0 ) { + /* try all, but report error at end */ + retcode = 1; + } } mi->mi_entry_limbo = NULL; } - return( 0 ); + return retcode; } int @@ -2342,7 +2488,8 @@ monitor_back_db_config( int monitor_back_db_destroy( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr) { monitor_info_t *mi = ( monitor_info_t * )be->be_private; @@ -2372,6 +2519,16 @@ monitor_back_db_destroy( ch_free( monitor_subsys ); } + + if ( mi->mi_entry_limbo ) { + entry_limbo_t *el = mi->mi_entry_limbo; + + for ( ; el; ) { + entry_limbo_t *tmp = el; + el = el->el_next; + monitor_back_destroy_limbo_entry( tmp, 1 ); + } + } ldap_pvt_thread_mutex_destroy( &monitor_info.mi_cache_mutex ); diff --git a/servers/slapd/back-monitor/log.c b/servers/slapd/back-monitor/log.c index c25261b07c..8f6d07d29f 100644 --- a/servers/slapd/back-monitor/log.c +++ b/servers/slapd/back-monitor/log.c @@ -111,7 +111,7 @@ monitor_subsys_log_modify( int rc = LDAP_OTHER; int newlevel = ldap_syslog; Attribute *save_attrs; - Modifications *modlist = op->oq_modify.rs_modlist; + Modifications *modlist = op->orm_modlist; Modifications *ml; ldap_pvt_thread_mutex_lock( &monitor_log_mutex ); diff --git a/servers/slapd/back-monitor/modify.c b/servers/slapd/back-monitor/modify.c index a8d6c887db..5001bfabcf 100644 --- a/servers/slapd/back-monitor/modify.c +++ b/servers/slapd/back-monitor/modify.c @@ -62,7 +62,7 @@ monitor_back_modify( Operation *op, SlapReply *rs ) return rs->sr_err; } - if ( !acl_check_modlist( op, e, op->oq_modify.rs_modlist )) { + if ( !acl_check_modlist( op, e, op->orm_modlist )) { rc = LDAP_INSUFFICIENT_ACCESS; } else { diff --git a/servers/slapd/back-monitor/operation.c b/servers/slapd/back-monitor/operation.c index 48bbcd5f70..74bd27402c 100644 --- a/servers/slapd/back-monitor/operation.c +++ b/servers/slapd/back-monitor/operation.c @@ -34,12 +34,12 @@ struct monitor_ops_t { } monitor_op[] = { { BER_BVC( "cn=Bind" ), BER_BVNULL }, { BER_BVC( "cn=Unbind" ), BER_BVNULL }, + { BER_BVC( "cn=Search" ), BER_BVNULL }, + { BER_BVC( "cn=Compare" ), BER_BVNULL }, + { BER_BVC( "cn=Modify" ), BER_BVNULL }, + { BER_BVC( "cn=Modrdn" ), BER_BVNULL }, { BER_BVC( "cn=Add" ), BER_BVNULL }, { BER_BVC( "cn=Delete" ), BER_BVNULL }, - { BER_BVC( "cn=Modrdn" ), BER_BVNULL }, - { BER_BVC( "cn=Modify" ), BER_BVNULL }, - { BER_BVC( "cn=Compare" ), BER_BVNULL }, - { BER_BVC( "cn=Search" ), BER_BVNULL }, { BER_BVC( "cn=Abandon" ), BER_BVNULL }, { BER_BVC( "cn=Extended" ), BER_BVNULL }, { BER_BVNULL, BER_BVNULL } diff --git a/servers/slapd/back-monitor/proto-back-monitor.h b/servers/slapd/back-monitor/proto-back-monitor.h index 66306e23ae..f09522db1f 100644 --- a/servers/slapd/back-monitor/proto-back-monitor.h +++ b/servers/slapd/back-monitor/proto-back-monitor.h @@ -135,8 +135,35 @@ monitor_entry_stub LDAP_P(( * init */ extern int +monitor_subsys_is_opened LDAP_P(( + void )); +extern int monitor_back_register_subsys LDAP_P(( monitor_subsys_t *ms )); +extern int +monitor_back_register_backend LDAP_P(( + BackendInfo *bi )); +extern int +monitor_back_register_database LDAP_P(( + BackendDB *be )); +extern int +monitor_back_register_overlay_info LDAP_P(( + slap_overinst *on )); +extern int +monitor_back_register_overlay LDAP_P(( + BackendDB *be )); +extern int +monitor_back_register_backend_limbo LDAP_P(( + BackendInfo *bi )); +extern int +monitor_back_register_database_limbo LDAP_P(( + BackendDB *be )); +extern int +monitor_back_register_overlay_info_limbo LDAP_P(( + slap_overinst *on )); +extern int +monitor_back_register_overlay_limbo LDAP_P(( + BackendDB *be )); extern monitor_subsys_t * monitor_back_get_subsys LDAP_P(( const char *name )); diff --git a/servers/slapd/back-monitor/time.c b/servers/slapd/back-monitor/time.c index 2d96339fa4..f3450d8315 100644 --- a/servers/slapd/back-monitor/time.c +++ b/servers/slapd/back-monitor/time.c @@ -46,7 +46,7 @@ monitor_subsys_time_init( Entry *e, **ep, *e_time; monitor_entry_t *mp; - struct berval bv; + struct berval bv, value; assert( be != NULL ); @@ -73,8 +73,8 @@ monitor_subsys_time_init( if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "monitor_subsys_time_init: " - "unable to create entry \"cn=Start,%s\"\n", - ms->mss_ndn.bv_val, 0, 0 ); + "unable to create entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); return( -1 ); } attr_merge_normalize_one( e, mi->mi_ad_monitorTimestamp, @@ -92,8 +92,8 @@ monitor_subsys_time_init( if ( monitor_cache_add( mi, e ) ) { Debug( LDAP_DEBUG_ANY, "monitor_subsys_time_init: " - "unable to add entry \"cn=Start,%s\"\n", - ms->mss_ndn.bv_val, 0, 0 ); + "unable to add entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); return( -1 ); } @@ -109,8 +109,8 @@ monitor_subsys_time_init( if ( e == NULL ) { Debug( LDAP_DEBUG_ANY, "monitor_subsys_time_init: " - "unable to create entry \"cn=Current,%s\"\n", - ms->mss_ndn.bv_val, 0, 0 ); + "unable to create entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); return( -1 ); } attr_merge_normalize_one( e, mi->mi_ad_monitorTimestamp, @@ -128,8 +128,45 @@ monitor_subsys_time_init( if ( monitor_cache_add( mi, e ) ) { Debug( LDAP_DEBUG_ANY, "monitor_subsys_time_init: " - "unable to add entry \"cn=Current,%s\"\n", - ms->mss_ndn.bv_val, 0, 0 ); + "unable to add entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); + return( -1 ); + } + + *ep = e; + ep = &mp->mp_next; + + /* + * Uptime + */ + BER_BVSTR( &bv, "cn=Uptime" ); + e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &bv, + mi->mi_oc_monitoredObject, mi, NULL, NULL ); + if ( e == NULL ) { + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_time_init: " + "unable to create entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); + return( -1 ); + } + BER_BVSTR( &value, "0" ); + attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, + &value, NULL ); + + mp = monitor_entrypriv_create(); + if ( mp == NULL ) { + return -1; + } + e->e_private = ( void * )mp; + mp->mp_info = ms; + mp->mp_flags = ms->mss_flags \ + | MONITOR_F_SUB | MONITOR_F_PERSISTENT; + + if ( monitor_cache_add( mi, e ) ) { + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_time_init: " + "unable to add entry \"%s,%s\"\n", + bv.bv_val, ms->mss_ndn.bv_val, 0 ); return( -1 ); } @@ -148,7 +185,8 @@ monitor_subsys_time_update( Entry *e ) { monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; - static struct berval bv_current = BER_BVC( "cn=current" ); + static struct berval bv_current = BER_BVC( "cn=current" ), + bv_uptime = BER_BVC( "cn=uptime" ); struct berval rdn; assert( mi != NULL ); @@ -200,6 +238,29 @@ monitor_subsys_time_update( assert( len == a->a_vals[ 0 ].bv_len ); AC_MEMCPY( a->a_vals[ 0 ].bv_val, tmbuf, len ); + /* FIXME: touch modifyTimestamp? */ + + } else if ( dn_match( &rdn, &bv_uptime ) ) { + Attribute *a; + double diff; + char buf[ BACKMONITOR_BUFSIZE ]; + struct berval bv; + + a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo ); + if ( a == NULL ) { + return rs->sr_err = LDAP_OTHER; + } + + diff = difftime( slap_get_time(), starttime ); + bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", + (unsigned long) diff ); + bv.bv_val = buf; + + ber_bvreplace( &a->a_vals[ 0 ], &bv ); + if ( a->a_nvals != a->a_vals ) { + ber_bvreplace( &a->a_nvals[ 0 ], &bv ); + } + /* FIXME: touch modifyTimestamp? */ } diff --git a/servers/slapd/back-null/null.c b/servers/slapd/back-null/null.c index 4fc58ef961..29673f9a42 100644 --- a/servers/slapd/back-null/null.c +++ b/servers/slapd/back-null/null.c @@ -24,6 +24,7 @@ #include #include "slap.h" +#include "config.h" struct null_info { int ni_bind_allowed; @@ -68,6 +69,20 @@ null_back_false( Operation *op, SlapReply *rs ) } +/* for overlays */ +int null_back_entry_get( + Operation *op, + struct berval *ndn, + ObjectClass *oc, + AttributeDescription *at, + int rw, + Entry **ent ) +{ + *ent = NULL; + return 1; +} + + /* Slap tools */ static int @@ -146,7 +161,7 @@ null_back_db_config( } static int -null_back_db_init( BackendDB *be ) +null_back_db_init( BackendDB *be, ConfigReply *cr ) { struct null_info *ni = ch_calloc( 1, sizeof(struct null_info) ); ni->ni_bind_allowed = 0; @@ -156,7 +171,7 @@ null_back_db_init( BackendDB *be ) } static int -null_back_db_destroy( Backend *be ) +null_back_db_destroy( Backend *be, ConfigReply *cr ) { free( be->be_private ); return 0; @@ -194,6 +209,8 @@ null_back_initialize( BackendInfo *bi ) bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; + bi->bi_entry_get_rw = null_back_entry_get; + bi->bi_tool_entry_open = null_tool_entry_open; bi->bi_tool_entry_close = null_tool_entry_close; bi->bi_tool_entry_first = null_tool_entry_next; diff --git a/servers/slapd/back-perl/SampleLDAP.pm b/servers/slapd/back-perl/SampleLDAP.pm index 4e20ff628c..ca1281267d 100644 --- a/servers/slapd/back-perl/SampleLDAP.pm +++ b/servers/slapd/back-perl/SampleLDAP.pm @@ -18,153 +18,151 @@ # # database perl # suffix "o=AnyOrg,c=US" -# perlModulePath /path/to/this/file +# perlModulePath /directory/containing/this/module # perlModule SampleLDAP +# +# See the slapd-perl(5) manual page for details. package SampleLDAP; - +use strict; +use warnings; use POSIX; -sub new -{ - my $class = shift; +$SampleLDAP::VERSION = '1.01'; + +sub new { + my $class = shift; - my $this = {}; - bless $this, $class; - print STDERR "Here in new\n"; - print STDERR "Posix Var " . BUFSIZ . " and " . FILENAME_MAX . "\n"; - return $this; + my $this = {}; + bless $this, $class; + print {*STDERR} "Here in new\n"; + print {*STDERR} 'Posix Var ' . BUFSIZ . ' and ' . FILENAME_MAX . "\n"; + return $this; } -sub init -{ - return 0; +sub init { + return 0; } -sub search -{ - my $this = shift; - my($base, $scope, $deref, $sizeLim, $timeLim, $filterStr, $attrOnly, @attrs ) = @_; - print STDERR "====$filterStr====\n"; - $filterStr =~ s/\(|\)//g; - $filterStr =~ s/=/: /; +sub search { + my $this = shift; + my ( $base, $scope, $deref, $sizeLim, $timeLim, $filterStr, $attrOnly, + @attrs ) + = @_; + print {*STDERR}, "====$filterStr====\n"; + $filterStr =~ s/\(|\)//gm; + $filterStr =~ s/=/: /m; - my @match_dn = (); - foreach my $dn ( keys %$this ) { - if ( $this->{ $dn } =~ /$filterStr/im ) { - push @match_dn, $dn; - last if ( scalar @match_dn == $sizeLim ); + my @match_dn = (); + for my $dn ( keys %{$this} ) { + if ( $this->{$dn} =~ /$filterStr/imx ) { + push @match_dn, $dn; + last if ( scalar @match_dn == $sizeLim ); - } - } + } + } - my @match_entries = (); - - foreach my $dn ( @match_dn ) { - push @match_entries, $this->{ $dn }; - } + my @match_entries = (); - return ( 0 , @match_entries ); + for my $dn (@match_dn) { + push @match_entries, $this->{$dn}; + } + + return ( 0, @match_entries ); } -sub compare -{ - my $this = shift; - my ( $dn, $avaStr ) = @_; - my $rc = 5; # LDAP_COMPARE_FALSE +sub compare { + my $this = shift; + my ( $dn, $avaStr ) = @_; + my $rc = 5; # LDAP_COMPARE_FALSE - $avaStr =~ s/=/: /; + $avaStr =~ s/=/: /m; - if ( $this->{ $dn } =~ /$avaStr/im ) { - $rc = 6; # LDAP_COMPARE_TRUE - } + if ( $this->{$dn} =~ /$avaStr/im ) { + $rc = 6; # LDAP_COMPARE_TRUE + } - return $rc; + return $rc; } -sub modify -{ - my $this = shift; +sub modify { + my $this = shift; - my ( $dn, @list ) = @_; + my ( $dn, @list ) = @_; - while ( @list > 0 ) { - my $action = shift @list; - my $key = shift @list; - my $value = shift @list; + while ( @list > 0 ) { + my $action = shift @list; + my $key = shift @list; + my $value = shift @list; - if( $action eq "ADD" ) { - $this->{ $dn } .= "$key: $value\n"; + if ( $action eq 'ADD' ) { + $this->{$dn} .= "$key: $value\n"; - } - elsif( $action eq "DELETE" ) { - $this->{ $dn } =~ s/^$key:\s*$value\n//mi ; + } + elsif ( $action eq 'DELETE' ) { + $this->{$dn} =~ s/^$key:\s*$value\n//im; - } - elsif( $action eq "REPLACE" ) { - $this->{ $dn } =~ s/$key: .*$/$key: $value/im ; - } - } + } + elsif ( $action eq 'REPLACE' ) { + $this->{$dn} =~ s/$key: .*$/$key: $value/im; + } + } - return 0; + return 0; } -sub add -{ - my $this = shift; - - my ( $entryStr ) = @_; +sub add { + my $this = shift; - my ( $dn ) = ( $entryStr =~ /dn:\s(.*)$/m ); + my ($entryStr) = @_; - # - # This needs to be here until a normalized dn is - # passed to this routine. - # - $dn = uc( $dn ); - $dn =~ s/\s*//g; + my ($dn) = ( $entryStr =~ /dn:\s(.*)$/m ); + # + # This needs to be here until a normalized dn is + # passed to this routine. + # + $dn = uc $dn; + $dn =~ s/\s*//gm; - $this->{$dn} = $entryStr; + $this->{$dn} = $entryStr; - return 0; + return 0; } -sub modrdn -{ - my $this = shift; +sub modrdn { + my $this = shift; - my ( $dn, $newdn, $delFlag ) = @_; + my ( $dn, $newdn, $delFlag ) = @_; - $this->{ $newdn } = $this->{ $dn }; + $this->{$newdn} = $this->{$dn}; - if( $delFlag ) { - delete $this->{ $dn }; - } - return 0; + if ($delFlag) { + delete $this->{$dn}; + } + return 0; } -sub delete -{ - my $this = shift; +sub delete { + my $this = shift; + + my ($dn) = @_; - my ( $dn ) = @_; - - print STDERR "XXXXXX $dn XXXXXXX\n"; - delete $this->{$dn}; + print {*STDERR} "XXXXXX $dn XXXXXXX\n"; + delete $this->{$dn}; + return 0; } -sub config -{ - my $this = shift; +sub config { + my $this = shift; - my ( @args ) = @_; - local $, = " - "; - print STDERR @args; - print STDERR "\n"; - return 0; + my (@args) = @_; + local $, = ' - '; + print {*STDERR} @args; + print {*STDERR} "\n"; + return 0; } 1; diff --git a/servers/slapd/back-perl/bind.c b/servers/slapd/back-perl/bind.c index 2e19370f49..878c48dfb0 100644 --- a/servers/slapd/back-perl/bind.c +++ b/servers/slapd/back-perl/bind.c @@ -32,6 +32,16 @@ perl_back_bind( PerlBackend *perl_back = (PerlBackend *) op->o_bd->be_private; + /* allow rootdn as a means to auth without the need to actually + * contact the proxied DSA */ + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + return rs->sr_err; + } + #if defined(HAVE_WIN32_ASPERL) || defined(USE_ITHREADS) PERL_SET_CONTEXT( PERL_INTERPRETER ); #endif diff --git a/servers/slapd/back-perl/close.c b/servers/slapd/back-perl/close.c index 4625797233..c1d0b05566 100644 --- a/servers/slapd/back-perl/close.c +++ b/servers/slapd/back-perl/close.c @@ -16,7 +16,7 @@ */ #include "perl_back.h" - +#include "../config.h" /********************************************************** * * Close @@ -39,7 +39,8 @@ perl_back_close( int perl_back_db_destroy( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { free( be->be_private ); diff --git a/servers/slapd/back-perl/init.c b/servers/slapd/back-perl/init.c index a695a8f97f..8d69a6fbc1 100644 --- a/servers/slapd/back-perl/init.c +++ b/servers/slapd/back-perl/init.c @@ -16,6 +16,7 @@ */ #include "perl_back.h" +#include "../config.h" static void perl_back_xs_init LDAP_P((PERL_BACK_XS_INIT_PARAMS)); EXT void boot_DynaLoader LDAP_P((PERL_BACK_BOOT_DYNALOADER_PARAMS)); @@ -85,7 +86,8 @@ perl_back_initialize( int perl_back_db_init( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { be->be_private = (PerlBackend *) ch_malloc( sizeof(PerlBackend) ); @@ -100,7 +102,8 @@ perl_back_db_init( int perl_back_db_open( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { int count; diff --git a/servers/slapd/back-relay/Makefile.in b/servers/slapd/back-relay/Makefile.in index 6ef139cbaf..75a6a81eff 100644 --- a/servers/slapd/back-relay/Makefile.in +++ b/servers/slapd/back-relay/Makefile.in @@ -13,8 +13,8 @@ ## top-level directory of the distribution or, alternatively, at ## . -SRCS = init.c config.c op.c -OBJS = init.lo config.lo op.lo +SRCS = init.c op.c +OBJS = init.lo op.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-relay/config.c b/servers/slapd/back-relay/config.c deleted file mode 100644 index 503da6e940..0000000000 --- a/servers/slapd/back-relay/config.c +++ /dev/null @@ -1,181 +0,0 @@ -/* config.c - relay backend configuration file routine */ -/* This work is part of OpenLDAP Software . - * - * Copyright 2004-2007 The OpenLDAP Foundation. - * Portions Copyright 2004 Pierangelo Masarati. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted only as authorized by the OpenLDAP - * Public License. - * - * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at - * . - */ -/* ACKNOWLEDGEMENTS: - * This work was initially developed by Pierangelo Masaratifor inclusion - * in OpenLDAP Software. - */ - -#include "portable.h" - -#include - -#include "slap.h" -#include "back-relay.h" - -int -relay_back_db_config( - BackendDB *be, - const char *fname, - int lineno, - int argc, - char **argv ) -{ - relay_back_info *ri = (struct relay_back_info *)be->be_private; - - if ( ri == NULL ) { - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: relay backend info is null.\n", - fname, lineno ); - return 1; - } - - /* real naming context */ - if ( strcasecmp( argv[ 0 ], "relay" ) == 0 ) { - struct berval dn, ndn, pdn; - int rc; - BackendDB *bd; - - switch ( argc ) { - case 3: - if ( strcmp( argv[ 2 ], "massage" ) != 0 ) { - Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "unknown arg[#2]=\"%s\" " - "in \"relay [massage]\" line\n", - fname, lineno, argv[ 2 ] ); - return 1; - } - - if ( be->be_nsuffix == NULL ) { - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "\"relay\" directive " - "must appear after \"suffix\".\n", - fname, lineno ); - return 1; - } - - if ( !BER_BVISNULL( &be->be_nsuffix[ 1 ] ) ) { - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "relayng of multiple suffix " - "database not supported.\n", - fname, lineno ); - return 1; - } - /* fallthru */ - - case 2: - break; - - case 1: - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: missing relay suffix " - "in \"relay [massage]\" line.\n", - fname, lineno ); - return 1; - - default: - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: extra cruft " - "in \"relay [massage]\" line.\n", - fname, lineno ); - return 1; - } - - if ( !BER_BVISNULL( &ri->ri_realsuffix ) ) { - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "relay dn already specified.\n", - fname, lineno ); - return 1; - } - - /* The man page says that the "relay" directive - * automatically instantiates slapo-rwm; I don't - * like this very much any more, I'd prefer to - * have automatic instantiation only when "massage" - * is specified, so one has better control on - * where the overlay gets instantiated, but this - * would break compatibility. One can still control - * where the overlay is instantiated by moving - * around the "relay" directive, although this could - * make slapd.conf a bit confusing. */ - if ( overlay_config( be, "rwm", -1, NULL ) ) { - Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: unable to install " - "rwm overlay " - "in \"relay [massage]\" line\n", - fname, lineno ); - return 1; - } - - dn.bv_val = argv[ 1 ]; - dn.bv_len = strlen( argv[ 1 ] ); - rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL ); - if ( rc != LDAP_SUCCESS ) { - Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "relay dn \"%s\" is invalid " - "in \"relay [massage]\" line\n", - fname, lineno, argv[ 1 ] ); - return 1; - } - - bd = select_backend( &ndn, 0, 1 ); - if ( bd == NULL ) { - Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "cannot find database " - "of relay dn \"%s\" " - "in \"relay [massage]\" line\n", - fname, lineno, argv[ 1 ] ); - rc = 1; - goto relay_done; - - } else if ( bd->be_private == be->be_private ) { - Log3( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: line %d: " - "relay dn \"%s\" would call self " - "in \"relay [massage]\" line\n", - fname, lineno, pdn.bv_val ); - rc = 1; - goto relay_done; - } - - ri->ri_realsuffix = ndn; - - if ( argc == 3 ) { - char *cargv[ 4 ]; - - cargv[ 0 ] = "rwm-suffixmassage"; - cargv[ 1 ] = be->be_suffix[0].bv_val; - cargv[ 2 ] = pdn.bv_val; - cargv[ 3 ] = NULL; - - rc = be->be_config( be, fname, lineno, 3, cargv ); - } - -relay_done:; - ch_free( pdn.bv_val ); - - return rc; - } - - /* anything else */ - return SLAP_CONF_UNKNOWN; -} - diff --git a/servers/slapd/back-relay/init.c b/servers/slapd/back-relay/init.c index c8219e1e20..f5c4241013 100644 --- a/servers/slapd/back-relay/init.c +++ b/servers/slapd/back-relay/init.c @@ -24,8 +24,116 @@ #include #include "slap.h" +#include "config.h" #include "back-relay.h" +static ConfigDriver relay_back_cf; + +static ConfigTable relaycfg[] = { + { "relay", "relay", 2, 2, 0, + ARG_MAGIC|ARG_DN, + relay_back_cf, "( OLcfgDbAt:5.1 " + "NAME 'olcRelay' " + "DESC 'Relay DN' " + "SYNTAX OMsDN " + "SINGLE-VALUE )", + NULL, NULL }, + { NULL } +}; + +static ConfigOCs relayocs[] = { + { "( OLcfgDbOc:5.1 " + "NAME 'olcRelayConfig' " + "DESC 'Relay backend configuration' " + "SUP olcDatabaseConfig " + "MAY ( olcRelay " + ") )", + Cft_Database, relaycfg}, + { NULL, 0, NULL } +}; + +static int +relay_back_cf( ConfigArgs *c ) +{ + relay_back_info *ri = ( relay_back_info * )c->be->be_private; + int rc = 0; + + if ( c->op == SLAP_CONFIG_EMIT ) { + if ( ri != NULL && !BER_BVISNULL( &ri->ri_realsuffix ) ) { + value_add_one( &c->rvalue_vals, &ri->ri_realsuffix ); + return 0; + } + return 1; + + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( !BER_BVISNULL( &ri->ri_realsuffix ) ) { + ch_free( ri->ri_realsuffix.bv_val ); + BER_BVZERO( &ri->ri_realsuffix ); + ri->ri_bd = NULL; + return 0; + } + return 1; + + } else { + BackendDB *bd; + + assert( ri != NULL ); + assert( BER_BVISNULL( &ri->ri_realsuffix ) ); + + if ( c->be->be_nsuffix == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg), + "\"relay\" directive " + "must appear after \"suffix\"" ); + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "%s: %s.\n", c->log, c->cr_msg ); + rc = 1; + goto relay_done; + } + + if ( !BER_BVISNULL( &c->be->be_nsuffix[ 1 ] ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg), + "relaying of multiple suffix " + "database not supported" ); + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "%s: %s.\n", c->log, c->cr_msg ); + rc = 1; + goto relay_done; + } + + bd = select_backend( &c->value_ndn, 1 ); + if ( bd == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg), + "cannot find database " + "of relay dn \"%s\" " + "in \"olcRelay \"\n", + c->value_dn.bv_val ); + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "%s: %s.\n", c->log, c->cr_msg ); + rc = 1; + goto relay_done; + + } else if ( bd->be_private == c->be->be_private ) { + snprintf( c->cr_msg, sizeof( c->cr_msg), + "relay dn \"%s\" would call self " + "in \"relay \" line\n", + c->value_dn.bv_val ); + Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "%s: %s.\n", c->log, c->cr_msg ); + rc = 1; + goto relay_done; + } + + ri->ri_realsuffix = c->value_ndn; + BER_BVZERO( &c->value_ndn ); + +relay_done:; + ch_free( c->value_dn.bv_val ); + ch_free( c->value_ndn.bv_val ); + } + + return rc; +} + int relay_back_initialize( BackendInfo *bi ) { @@ -36,10 +144,10 @@ relay_back_initialize( BackendInfo *bi ) bi->bi_destroy = 0; bi->bi_db_init = relay_back_db_init; - bi->bi_db_config = relay_back_db_config; + bi->bi_db_config = config_generic_wrapper; bi->bi_db_open = relay_back_db_open; #if 0 - bi->bi_db_close =relay_back_db_close; + bi->bi_db_close = relay_back_db_close; #endif bi->bi_db_destroy = relay_back_db_destroy; @@ -65,11 +173,13 @@ relay_back_initialize( BackendInfo *bi ) bi->bi_connection_init = relay_back_connection_init; bi->bi_connection_destroy = relay_back_connection_destroy; - return 0; + bi->bi_cf_ocs = relayocs; + + return config_register_schema( relaycfg, relayocs ); } int -relay_back_db_init( Backend *be ) +relay_back_db_init( Backend *be, ConfigReply *cr) { relay_back_info *ri; @@ -84,20 +194,22 @@ relay_back_db_init( Backend *be ) BER_BVZERO( &ri->ri_realsuffix ); ri->ri_massage = 0; + be->be_cf_ocs = be->bd_info->bi_cf_ocs; + be->be_private = (void *)ri; return 0; } int -relay_back_db_open( Backend *be ) +relay_back_db_open( Backend *be, ConfigReply *cr ) { relay_back_info *ri = (relay_back_info *)be->be_private; assert( ri != NULL ); if ( !BER_BVISNULL( &ri->ri_realsuffix ) ) { - ri->ri_bd = select_backend( &ri->ri_realsuffix, 0, 1 ); + ri->ri_bd = select_backend( &ri->ri_realsuffix, 1 ); /* must be there: it was during config! */ assert( ri->ri_bd != NULL ); @@ -114,13 +226,13 @@ relay_back_db_open( Backend *be ) } int -relay_back_db_close( Backend *be ) +relay_back_db_close( Backend *be, ConfigReply *cr ) { return 0; } int -relay_back_db_destroy( Backend *be ) +relay_back_db_destroy( Backend *be, ConfigReply *cr) { relay_back_info *ri = (relay_back_info *)be->be_private; diff --git a/servers/slapd/back-relay/op.c b/servers/slapd/back-relay/op.c index 0c463cc203..0616472458 100644 --- a/servers/slapd/back-relay/op.c +++ b/servers/slapd/back-relay/op.c @@ -26,7 +26,7 @@ #include "back-relay.h" static int -relay_back_swap_bd( struct slap_op *op, struct slap_rep *rs ) +relay_back_swap_bd( Operation *op, SlapReply *rs ) { slap_callback *cb = op->o_callback; BackendDB *be = op->o_bd; @@ -38,7 +38,7 @@ relay_back_swap_bd( struct slap_op *op, struct slap_rep *rs ) } static void -relay_back_add_cb( slap_callback *cb, struct slap_op *op ) +relay_back_add_cb( slap_callback *cb, Operation *op ) { cb->sc_next = op->o_callback; cb->sc_response = relay_back_swap_bd; @@ -55,15 +55,15 @@ relay_back_add_cb( slap_callback *cb, struct slap_op *op ) * any valid error send as error result */ static BackendDB * -relay_back_select_backend( struct slap_op *op, struct slap_rep *rs, int err ) +relay_back_select_backend( Operation *op, SlapReply *rs, int err, int dosend ) { relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; BackendDB *bd = ri->ri_bd; - if ( bd == NULL ) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); + if ( bd == NULL && !BER_BVISNULL( &op->o_req_ndn ) ) { + bd = select_backend( &op->o_req_ndn, 1 ); if ( bd == op->o_bd ) { - if ( err > LDAP_SUCCESS ) { + if ( err > LDAP_SUCCESS && dosend ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "back-relay would call self" ); @@ -74,17 +74,21 @@ relay_back_select_backend( struct slap_op *op, struct slap_rep *rs, int err ) if ( bd == NULL && err > -1 ) { if ( default_referral ) { - rs->sr_ref = referral_rewrite( default_referral, - NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); - if ( !rs->sr_ref ) { - rs->sr_ref = default_referral; - } - rs->sr_err = LDAP_REFERRAL; - send_ldap_result( op, rs ); - - if ( rs->sr_ref != default_referral ) { - ber_bvarray_free( rs->sr_ref ); + if ( dosend ) { + rs->sr_ref = referral_rewrite( + default_referral, + NULL, &op->o_req_dn, + LDAP_SCOPE_DEFAULT ); + if ( !rs->sr_ref ) { + rs->sr_ref = default_referral; + } + + send_ldap_result( op, rs ); + + if ( rs->sr_ref != default_referral ) { + ber_bvarray_free( rs->sr_ref ); + } } } else { @@ -92,7 +96,9 @@ relay_back_select_backend( struct slap_op *op, struct slap_rep *rs, int err ) * LDAP_NO_SUCH_OBJECT for other operations. * noSuchObject cannot be returned by bind */ rs->sr_err = err; - send_ldap_result( op, rs ); + if ( dosend ) { + send_ldap_result( op, rs ); + } } } @@ -100,12 +106,22 @@ relay_back_select_backend( struct slap_op *op, struct slap_rep *rs, int err ) } int -relay_back_op_bind( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_bind( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_INVALID_CREDENTIALS ); + /* allow rootdn as a means to auth without the need to actually + * contact the proxied DSA */ + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + return rs->sr_err; + } + + bd = relay_back_select_backend( op, rs, LDAP_INVALID_CREDENTIALS, 1 ); if ( bd == NULL ) { return rc; } @@ -117,7 +133,7 @@ relay_back_op_bind( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_bind )( op, rs ); + rc = bd->be_bind( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -134,15 +150,14 @@ relay_back_op_bind( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_unbind( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_unbind( Operation *op, SlapReply *rs ) { - relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; BackendDB *bd; int rc = 1; - bd = ri->ri_bd; + bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 ); if ( bd == NULL ) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); + return 1; } if ( bd && bd->be_unbind ) { @@ -152,7 +167,7 @@ relay_back_op_unbind( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_unbind )( op, rs ); + rc = bd->be_unbind( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -165,12 +180,12 @@ relay_back_op_unbind( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_search( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_search( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -182,7 +197,7 @@ relay_back_op_search( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_search )( op, rs ); + rc = bd->be_search( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -200,12 +215,12 @@ relay_back_op_search( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_compare( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_compare( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -217,7 +232,7 @@ relay_back_op_compare( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_compare )( op, rs ); + rc = bd->be_compare( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -235,12 +250,12 @@ relay_back_op_compare( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_modify( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_modify( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -252,7 +267,7 @@ relay_back_op_modify( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_modify )( op, rs ); + rc = bd->be_modify( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -270,12 +285,12 @@ relay_back_op_modify( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_modrdn( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_modrdn( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -287,7 +302,7 @@ relay_back_op_modrdn( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_modrdn )( op, rs ); + rc = bd->be_modrdn( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -305,12 +320,12 @@ relay_back_op_modrdn( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_add( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_add( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -322,7 +337,7 @@ relay_back_op_add( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_add )( op, rs ); + rc = bd->be_add( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -340,12 +355,12 @@ relay_back_op_add( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_delete( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_delete( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 1 ); if ( bd == NULL ) { return 1; } @@ -357,7 +372,7 @@ relay_back_op_delete( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_delete )( op, rs ); + rc = bd->be_delete( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -370,12 +385,12 @@ relay_back_op_delete( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_abandon( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_abandon( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, -1 ); + bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 ); if ( bd == NULL ) { return 1; } @@ -387,7 +402,7 @@ relay_back_op_abandon( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_abandon )( op, rs ); + rc = bd->be_abandon( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -400,12 +415,12 @@ relay_back_op_abandon( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_cancel( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_cancel( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_CANNOT_CANCEL, 0 ); if ( bd == NULL ) { return 1; } @@ -417,7 +432,7 @@ relay_back_op_cancel( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_cancel )( op, rs ); + rc = bd->be_cancel( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -435,12 +450,12 @@ relay_back_op_cancel( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_op_extended( struct slap_op *op, struct slap_rep *rs ) +relay_back_op_extended( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 1; - bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT ); + bd = relay_back_select_backend( op, rs, LDAP_NO_SUCH_OBJECT, 0 ); if ( bd == NULL ) { return 1; } @@ -452,7 +467,7 @@ relay_back_op_extended( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_extended )( op, rs ); + rc = bd->be_extended( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -470,7 +485,7 @@ relay_back_op_extended( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_entry_release_rw( struct slap_op *op, Entry *e, int rw ) +relay_back_entry_release_rw( Operation *op, Entry *e, int rw ) { relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; BackendDB *bd; @@ -478,7 +493,7 @@ relay_back_entry_release_rw( struct slap_op *op, Entry *e, int rw ) bd = ri->ri_bd; if ( bd == NULL) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); + bd = select_backend( &op->o_req_ndn, 1 ); if ( bd == NULL ) { return 1; } @@ -488,7 +503,7 @@ relay_back_entry_release_rw( struct slap_op *op, Entry *e, int rw ) BackendDB *be = op->o_bd; op->o_bd = bd; - rc = ( bd->be_release )( op, e, rw ); + rc = bd->be_release( op, e, rw ); op->o_bd = be; } @@ -497,7 +512,7 @@ relay_back_entry_release_rw( struct slap_op *op, Entry *e, int rw ) } int -relay_back_entry_get_rw( struct slap_op *op, struct berval *ndn, +relay_back_entry_get_rw( Operation *op, struct berval *ndn, ObjectClass *oc, AttributeDescription *at, int rw, Entry **e ) { relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; @@ -506,7 +521,7 @@ relay_back_entry_get_rw( struct slap_op *op, struct berval *ndn, bd = ri->ri_bd; if ( bd == NULL) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); + bd = select_backend( &op->o_req_ndn, 1 ); if ( bd == NULL ) { return 1; } @@ -516,7 +531,7 @@ relay_back_entry_get_rw( struct slap_op *op, struct berval *ndn, BackendDB *be = op->o_bd; op->o_bd = bd; - rc = ( bd->be_fetch )( op, ndn, oc, at, rw, e ); + rc = bd->be_fetch( op, ndn, oc, at, rw, e ); op->o_bd = be; } @@ -532,12 +547,12 @@ relay_back_entry_get_rw( struct slap_op *op, struct berval *ndn, * naming context... mmmh. */ int -relay_back_chk_referrals( struct slap_op *op, struct slap_rep *rs ) +relay_back_chk_referrals( Operation *op, SlapReply *rs ) { BackendDB *bd; int rc = 0; - bd = relay_back_select_backend( op, rs, LDAP_SUCCESS ); + bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 1 ); /* FIXME: this test only works if there are no overlays, so * it is nearly useless; if made stricter, no nested back-relays * can be instantiated... too bad. */ @@ -561,7 +576,7 @@ relay_back_chk_referrals( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_chk_referrals )( op, rs ); + rc = bd->be_chk_referrals( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -574,18 +589,17 @@ relay_back_chk_referrals( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_operational( struct slap_op *op, struct slap_rep *rs ) +relay_back_operational( Operation *op, SlapReply *rs ) { - relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; BackendDB *bd; int rc = 1; - bd = ri->ri_bd; - if ( bd == NULL) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); - if ( bd == NULL ) { - return 1; - } + bd = relay_back_select_backend( op, rs, LDAP_SUCCESS, 0 ); + /* FIXME: this test only works if there are no overlays, so + * it is nearly useless; if made stricter, no nested back-relays + * can be instantiated... too bad. */ + if ( bd == NULL || bd == op->o_bd ) { + return 0; } if ( bd->be_operational ) { @@ -595,7 +609,7 @@ relay_back_operational( struct slap_op *op, struct slap_rep *rs ) relay_back_add_cb( &cb, op ); op->o_bd = bd; - rc = ( bd->be_operational )( op, rs ); + rc = bd->be_operational( op, rs ); op->o_bd = be; if ( op->o_callback == &cb ) { @@ -608,25 +622,25 @@ relay_back_operational( struct slap_op *op, struct slap_rep *rs ) } int -relay_back_has_subordinates( struct slap_op *op, Entry *e, int *hasSubs ) +relay_back_has_subordinates( Operation *op, Entry *e, int *hasSubs ) { - relay_back_info *ri = (relay_back_info *)op->o_bd->be_private; + SlapReply rs = { 0 }; BackendDB *bd; int rc = 1; - bd = ri->ri_bd; - if ( bd == NULL) { - bd = select_backend( &op->o_req_ndn, 0, 1 ); - if ( bd == NULL ) { - return 1; - } + bd = relay_back_select_backend( op, &rs, LDAP_SUCCESS, 0 ); + /* FIXME: this test only works if there are no overlays, so + * it is nearly useless; if made stricter, no nested back-relays + * can be instantiated... too bad. */ + if ( bd == NULL || bd == op->o_bd ) { + return 0; } if ( bd->be_has_subordinates ) { BackendDB *be = op->o_bd; op->o_bd = bd; - rc = ( bd->be_has_subordinates )( op, e, hasSubs ); + rc = bd->be_has_subordinates( op, e, hasSubs ); op->o_bd = be; } @@ -635,7 +649,7 @@ relay_back_has_subordinates( struct slap_op *op, Entry *e, int *hasSubs ) } int -relay_back_connection_init( BackendDB *bd, struct slap_conn *c ) +relay_back_connection_init( BackendDB *bd, Connection *c ) { relay_back_info *ri = (relay_back_info *)bd->be_private; @@ -645,24 +659,24 @@ relay_back_connection_init( BackendDB *bd, struct slap_conn *c ) } if ( bd->be_connection_init ) { - return ( bd->be_connection_init )( bd, c ); + return bd->be_connection_init( bd, c ); } return 0; } int -relay_back_connection_destroy( BackendDB *bd, struct slap_conn *c ) +relay_back_connection_destroy( BackendDB *bd, Connection *c ) { relay_back_info *ri = (relay_back_info *)bd->be_private; bd = ri->ri_bd; - if ( bd == NULL) { + if ( bd == NULL ) { return 0; } if ( bd->be_connection_destroy ) { - return ( bd->be_connection_destroy )( bd, c ); + return bd->be_connection_destroy( bd, c ); } return 0; diff --git a/servers/slapd/back-relay/proto-back-relay.h b/servers/slapd/back-relay/proto-back-relay.h index 97ba1c5564..c3945e3145 100644 --- a/servers/slapd/back-relay/proto-back-relay.h +++ b/servers/slapd/back-relay/proto-back-relay.h @@ -27,7 +27,6 @@ LDAP_BEGIN_DECL extern BI_init relay_back_initialize; extern BI_db_init relay_back_db_init; -extern BI_db_config relay_back_db_config; extern BI_db_open relay_back_db_open; extern BI_db_close relay_back_db_close; extern BI_db_destroy relay_back_db_destroy; diff --git a/servers/slapd/back-shell/bind.c b/servers/slapd/back-shell/bind.c index 32d8865e3d..dcbbcd4ba8 100644 --- a/servers/slapd/back-shell/bind.c +++ b/servers/slapd/back-shell/bind.c @@ -49,6 +49,16 @@ shell_back_bind( FILE *rfp, *wfp; int rc; + /* allow rootdn as a means to auth without the need to actually + * contact the proxied DSA */ + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + return rs->sr_err; + } + if ( si->si_bind == NULL ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "bind not implemented" ); diff --git a/servers/slapd/back-shell/init.c b/servers/slapd/back-shell/init.c index 5724118e5a..db9a91d2c8 100644 --- a/servers/slapd/back-shell/init.c +++ b/servers/slapd/back-shell/init.c @@ -36,6 +36,8 @@ #include "slap.h" +#include "config.h" + #include "shell.h" int @@ -76,7 +78,8 @@ shell_back_initialize( int shell_back_db_init( - Backend *be + Backend *be, + ConfigReply *cr ) { struct shellinfo *si; @@ -90,7 +93,8 @@ shell_back_db_init( int shell_back_db_destroy( - Backend *be + Backend *be, + ConfigReply *cr ) { free( be->be_private ); diff --git a/servers/slapd/back-shell/modify.c b/servers/slapd/back-shell/modify.c index 277c3c1dcd..d87a9bcccf 100644 --- a/servers/slapd/back-shell/modify.c +++ b/servers/slapd/back-shell/modify.c @@ -46,7 +46,7 @@ shell_back_modify( Modification *mod; struct shellinfo *si = (struct shellinfo *) op->o_bd->be_private; AttributeDescription *entry = slap_schema.si_ad_entry; - Modifications *ml = op->oq_modify.rs_modlist; + Modifications *ml = op->orm_modlist; Entry e; FILE *rfp, *wfp; int i; diff --git a/servers/slapd/back-shell/shell.h b/servers/slapd/back-shell/shell.h index 1540665173..ee4871b06b 100644 --- a/servers/slapd/back-shell/shell.h +++ b/servers/slapd/back-shell/shell.h @@ -46,10 +46,6 @@ struct shellinfo { char **si_delete; /* cmd + args to exec for delete */ }; -struct slap_backend_db; -struct slap_conn; -struct slap_op; - extern pid_t forkandexec LDAP_P(( char **args, FILE **rfp, @@ -57,11 +53,11 @@ extern pid_t forkandexec LDAP_P(( extern void print_suffixes LDAP_P(( FILE *fp, - struct slap_backend_db *bd)); + BackendDB *bd)); extern int read_and_send_results LDAP_P(( - struct slap_op *op, - struct slap_rep *rs, + Operation *op, + SlapReply *rs, FILE *fp)); LDAP_END_DECL diff --git a/servers/slapd/back-sql/add.c b/servers/slapd/back-sql/add.c index ed10958b67..501c8bfd96 100644 --- a/servers/slapd/back-sql/add.c +++ b/servers/slapd/back-sql/add.c @@ -1520,7 +1520,7 @@ done:; } if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &p.e_nname ) ) { diff --git a/servers/slapd/back-sql/back-sql.h b/servers/slapd/back-sql/back-sql.h index f214679148..98d06bc5e6 100644 --- a/servers/slapd/back-sql/back-sql.h +++ b/servers/slapd/back-sql/back-sql.h @@ -181,6 +181,7 @@ typedef struct { SWORD ncols; BerVarray col_names; UDWORD *col_prec; + SQLSMALLINT *col_type; char **cols; SQLINTEGER *value_len; } BACKSQL_ROW_NTS; @@ -265,31 +266,6 @@ typedef struct backsql_api { struct backsql_api *ba_next; } backsql_api; -/* - * Entry ID structure - */ -typedef struct backsql_entryID { - /* #define BACKSQL_ARBITRARY_KEY to allow a non-numeric key. - * It is required by some special applications that use - * strings as keys for the main table. - * In this case, #define BACKSQL_MAX_KEY_LEN consistently - * with the key size definition */ -#ifdef BACKSQL_ARBITRARY_KEY - struct berval eid_id; - struct berval eid_keyval; -#define BACKSQL_MAX_KEY_LEN 64 -#else /* ! BACKSQL_ARBITRARY_KEY */ - /* The original numeric key is maintained as default. */ - unsigned long eid_id; - unsigned long eid_keyval; -#endif /* ! BACKSQL_ARBITRARY_KEY */ - - unsigned long eid_oc_id; - struct berval eid_dn; - struct berval eid_ndn; - struct backsql_entryID *eid_next; -} backsql_entryID; - #ifdef BACKSQL_ARBITRARY_KEY #define BACKSQL_ENTRYID_INIT { BER_BVNULL, BER_BVNULL, 0, BER_BVNULL, BER_BVNULL, NULL } #else /* ! BACKSQL_ARBITRARY_KEY */ @@ -330,6 +306,7 @@ typedef struct backsql_oc_map_rec { typedef struct backsql_at_map_rec { /* Description of corresponding LDAP attribute type */ AttributeDescription *bam_ad; + AttributeDescription *bam_true_ad; /* ObjectClass if bam_ad is objectClass */ ObjectClass *bam_oc; @@ -395,14 +372,43 @@ typedef struct berbuf { #define BB_NULL { BER_BVNULL, 0 } +/* + * Entry ID structure + */ +typedef struct backsql_entryID { + /* #define BACKSQL_ARBITRARY_KEY to allow a non-numeric key. + * It is required by some special applications that use + * strings as keys for the main table. + * In this case, #define BACKSQL_MAX_KEY_LEN consistently + * with the key size definition */ +#ifdef BACKSQL_ARBITRARY_KEY + struct berval eid_id; + struct berval eid_keyval; +#define BACKSQL_MAX_KEY_LEN 64 +#else /* ! BACKSQL_ARBITRARY_KEY */ + /* The original numeric key is maintained as default. */ + unsigned long eid_id; + unsigned long eid_keyval; +#endif /* ! BACKSQL_ARBITRARY_KEY */ + + unsigned long eid_oc_id; + backsql_oc_map_rec *eid_oc; + struct berval eid_dn; + struct berval eid_ndn; + struct backsql_entryID *eid_next; +} backsql_entryID; + /* the function must collect the entry associated to nbase */ #define BACKSQL_ISF_GET_ID 0x1U #define BACKSQL_ISF_GET_ENTRY ( 0x2U | BACKSQL_ISF_GET_ID ) -#define BACKSQL_ISF_MATCHED 0x4U +#define BACKSQL_ISF_GET_OC ( 0x4U | BACKSQL_ISF_GET_ID ) +#define BACKSQL_ISF_MATCHED 0x8U #define BACKSQL_IS_GET_ID(f) \ ( ( (f) & BACKSQL_ISF_GET_ID ) == BACKSQL_ISF_GET_ID ) #define BACKSQL_IS_GET_ENTRY(f) \ ( ( (f) & BACKSQL_ISF_GET_ENTRY ) == BACKSQL_ISF_GET_ENTRY ) +#define BACKSQL_IS_GET_OC(f) \ + ( ( (f) & BACKSQL_ISF_GET_OC ) == BACKSQL_ISF_GET_OC ) #define BACKSQL_IS_MATCHED(f) \ ( ( (f) & BACKSQL_ISF_MATCHED ) == BACKSQL_ISF_MATCHED ) typedef struct backsql_srch_info { @@ -471,14 +477,16 @@ typedef struct backsql_info { */ struct berval sql_subtree_cond; struct berval sql_children_cond; - char *sql_oc_query, - *sql_at_query; - char *sql_insentry_stmt, - *sql_delentry_stmt, - *sql_renentry_stmt, - *sql_delobjclasses_stmt; + struct berval sql_dn_match_cond; + char *sql_oc_query; + char *sql_at_query; + char *sql_insentry_stmt; + char *sql_delentry_stmt; + char *sql_renentry_stmt; + char *sql_delobjclasses_stmt; char *sql_id_query; char *sql_has_children_query; + char *sql_list_children_query; MatchingRule *sql_caseIgnoreMatch; MatchingRule *sql_telephoneNumberMatch; @@ -556,9 +564,10 @@ typedef struct backsql_info { #define BACKSQL_BASEOBJECT_OC 0 Avlnode *sql_db_conns; + SQLHDBC sql_dbh; + ldap_pvt_thread_mutex_t sql_dbconn_mutex; Avlnode *sql_oc_by_oc; Avlnode *sql_oc_by_id; - ldap_pvt_thread_mutex_t sql_dbconn_mutex; ldap_pvt_thread_mutex_t sql_schema_mutex; SQLHENV sql_db_env; @@ -582,5 +591,10 @@ typedef struct backsql_info { #define BACKSQL_SANITIZE_ERROR( rc ) \ ( BACKSQL_LEGAL_ERROR( (rc) ) ? (rc) : LDAP_OTHER ) +#define BACKSQL_IS_BINARY(ct) \ + ( (ct) == SQL_BINARY \ + || (ct) == SQL_VARBINARY \ + || (ct) == SQL_LONGVARBINARY) + #endif /* __BACKSQL_H__ */ diff --git a/servers/slapd/back-sql/bind.c b/servers/slapd/back-sql/bind.c index 7db1ac8e5d..e76b8dbca6 100644 --- a/servers/slapd/back-sql/bind.c +++ b/servers/slapd/back-sql/bind.c @@ -40,27 +40,20 @@ backsql_bind( Operation *op, SlapReply *rs ) Debug( LDAP_DEBUG_TRACE, "==>backsql_bind()\n", 0, 0, 0 ); - if ( be_isroot_pw( op ) ) { - ber_dupbv( &op->oq_bind.rb_edn, be_root_dn( op->o_bd ) ); - Debug( LDAP_DEBUG_TRACE, "<==backsql_bind() root bind\n", - 0, 0, 0 ); - return LDAP_SUCCESS; - } - - ber_dupbv( &op->oq_bind.rb_edn, &op->o_req_ndn ); - - if ( op->oq_bind.rb_method != LDAP_AUTH_SIMPLE ) { - rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED; - rs->sr_text = "authentication method not supported"; - send_ldap_result( op, rs ); + switch ( be_rootdn_bind( op, rs ) ) { + case SLAP_CB_CONTINUE: + break; + + default: + /* in case of success, front end will send result; + * otherwise, be_rootdn_bind() did */ + Debug( LDAP_DEBUG_TRACE, "<==backsql_bind(%d)\n", + rs->sr_err, 0, 0 ); return rs->sr_err; } - /* - * method = LDAP_AUTH_SIMPLE - */ rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( !dbh ) { + if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_bind(): " "could not get connection handle - exiting\n", 0, 0, 0 ); @@ -101,7 +94,7 @@ backsql_bind( Operation *op, SlapReply *rs ) error_return:; if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &e.e_nname ) ) { diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c index 8ac1d96b04..24fe2e9fb1 100644 --- a/servers/slapd/back-sql/compare.c +++ b/servers/slapd/back-sql/compare.c @@ -42,7 +42,7 @@ backsql_compare( Operation *op, SlapReply *rs ) Debug( LDAP_DEBUG_TRACE, "==>backsql_compare()\n", 0, 0, 0 ); rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( !dbh ) { + if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " "could not get connection handle - exiting\n", 0, 0, 0 ); @@ -173,7 +173,7 @@ return_results:; } if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &e.e_nname ) ) { diff --git a/servers/slapd/back-sql/config.c b/servers/slapd/back-sql/config.c index e9857fa760..db1170c884 100644 --- a/servers/slapd/back-sql/config.c +++ b/servers/slapd/back-sql/config.c @@ -148,7 +148,20 @@ backsql_db_config( } ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_children_cond ); Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): " - "subtree_cond=%s\n", bi->sql_children_cond.bv_val, 0, 0 ); + "children_cond=%s\n", bi->sql_children_cond.bv_val, 0, 0 ); + + } else if ( !strcasecmp( argv[ 0 ], "dn_match_cond" ) ) { + if ( argc < 2 ) { + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): " + "missing SQL condition " + "in \"dn_match_cond\" directive\n", + fname, lineno, 0 ); + return 1; + } + ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_dn_match_cond ); + Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): " + "children_cond=%s\n", bi->sql_dn_match_cond.bv_val, 0, 0 ); } else if ( !strcasecmp( argv[ 0 ], "oc_query" ) ) { if ( argc < 2 ) { diff --git a/servers/slapd/back-sql/delete.c b/servers/slapd/back-sql/delete.c index 2bfddfda6c..c04acb0a8d 100644 --- a/servers/slapd/back-sql/delete.c +++ b/servers/slapd/back-sql/delete.c @@ -58,8 +58,7 @@ backsql_delete_all_attrs( Operation *op, SlapReply *rs, SQLHDBC dbh, - backsql_entryID *e_id, - backsql_oc_map_rec *oc ) + backsql_entryID *eid ) { backsql_delete_attr_t bda; int rc; @@ -67,9 +66,9 @@ backsql_delete_all_attrs( bda.op = op; bda.rs = rs; bda.dbh = dbh; - bda.e_id = e_id; + bda.e_id = eid; - rc = avl_apply( oc->bom_attrs, backsql_delete_attr_f, &bda, + rc = avl_apply( eid->eid_oc->bom_attrs, backsql_delete_attr_f, &bda, BACKSQL_AVL_STOP, AVL_INORDER ); if ( rc == BACKSQL_AVL_STOP ) { return rs->sr_err; @@ -78,187 +77,31 @@ backsql_delete_all_attrs( return LDAP_SUCCESS; } -int -backsql_delete( Operation *op, SlapReply *rs ) +static int +backsql_delete_int( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + SQLHSTMT *sthp, + backsql_entryID *eid, + Entry **ep ) { backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh = SQL_NULL_HDBC; SQLHSTMT sth = SQL_NULL_HSTMT; RETCODE rc; int prc = LDAP_SUCCESS; - backsql_oc_map_rec *oc = NULL; - backsql_srch_info bsi = { 0 }; - backsql_entryID e_id = { 0 }; - Entry d = { 0 }, p = { 0 }, *e = NULL; - struct berval pdn = BER_BVNULL; - int manageDSAit = get_manageDSAit( op ); /* first parameter no */ SQLUSMALLINT pno = 0; - Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", - op->o_req_ndn.bv_val, 0, 0 ); - - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - e = NULL; - goto done; - } - - /* - * Get the entry - */ - bsi.bsi_e = &d; - rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, - LDAP_SCOPE_BASE, - (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, - ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); - switch ( rs->sr_err ) { - case LDAP_SUCCESS: - break; - - case LDAP_REFERRAL: - if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && - dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) - { - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; - rs->sr_matched = NULL; - if ( rs->sr_ref ) { - ber_bvarray_free( rs->sr_ref ); - rs->sr_ref = NULL; - } - break; - } - e = &d; - /* fallthru */ - - default: - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "could not retrieve deleteDN ID - no such entry\n", - 0, 0, 0 ); - if ( !BER_BVISNULL( &d.e_nname ) ) { - /* FIXME: should always be true! */ - e = &d; - - } else { - e = NULL; - } - goto done; - } - - if ( get_assert( op ) && - ( test_filter( op, &d, get_assertion( op ) ) - != LDAP_COMPARE_TRUE ) ) - { - rs->sr_err = LDAP_ASSERTION_FAILED; - e = &d; - goto done; - } - - if ( !access_allowed( op, &d, slap_schema.si_ad_entry, - NULL, ACL_WDEL, NULL ) ) - { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "no write access to entry\n", - 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - e = &d; - goto done; - } - - rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn ); - switch ( rs->sr_err ) { - case LDAP_COMPARE_FALSE: - rs->sr_err = LDAP_SUCCESS; - break; - - case LDAP_COMPARE_TRUE: - if ( get_treeDelete( op ) ) { - /* not supported yet */ ; - } - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "entry \"%s\" has children\n", - op->o_req_dn.bv_val, 0, 0 ); - rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; - rs->sr_text = "subordinate objects must be deleted first"; - /* fallthru */ - - default: - e = &d; - goto done; - } - - oc = backsql_id2oc( bi, bsi.bsi_base_id.eid_oc_id ); - if ( oc == NULL ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "cannot determine objectclass of entry -- aborting\n", - 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - e = NULL; - goto done; - } - - if ( oc->bom_delete_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "delete procedure is not defined " - "for this objectclass - aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - e = NULL; - goto done; - } - - /* - * Get the parent - */ - e_id = bsi.bsi_base_id; - if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) { - dnParent( &op->o_req_ndn, &pdn ); - bsi.bsi_e = &p; - rs->sr_err = backsql_init_search( &bsi, &pdn, - LDAP_SCOPE_BASE, - (time_t)(-1), NULL, dbh, op, rs, - slap_anlist_no_attrs, - BACKSQL_ISF_GET_ENTRY ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "could not retrieve deleteDN ID " - "- no such entry\n", - 0, 0, 0 ); - e = &p; - goto done; - } - - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); - - /* check parent for "children" acl */ - if ( !access_allowed( op, &p, slap_schema.si_ad_children, - NULL, ACL_WDEL, NULL ) ) - { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "no write access to parent\n", - 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - e = &p; - goto done; - - } - } + sth = *sthp; /* avl_apply ... */ - rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, &e_id, oc ); + rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, eid ); if ( rs->sr_err != LDAP_SUCCESS ) { - e = &d; goto done; } - rc = backsql_Prepare( dbh, &sth, oc->bom_delete_proc, 0 ); + rc = backsql_Prepare( dbh, &sth, eid->eid_oc->bom_delete_proc, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " @@ -268,42 +111,42 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - e = NULL; + *ep = NULL; goto done; } - if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) { + if ( BACKSQL_IS_DEL( eid->eid_oc->bom_expect_return ) ) { pno = 1; rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding output parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; - e = NULL; + *ep = NULL; goto done; } } - rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &e_id.eid_keyval ); + rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &eid->eid_keyval ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding keyval parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; - e = NULL; + *ep = NULL; goto done; } @@ -328,7 +171,6 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; } SQLFreeStmt( sth, SQL_DROP ); - e = &d; goto done; } SQLFreeStmt( sth, SQL_DROP ); @@ -344,24 +186,24 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - e = NULL; + *ep = NULL; goto done; } - rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id ); + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding auxiliary objectClasses " "entry ID parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; - e = NULL; + *ep = NULL; goto done; } @@ -381,7 +223,7 @@ backsql_delete( Operation *op, SlapReply *rs ) SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - e = NULL; + *ep = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); @@ -397,24 +239,24 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - e = NULL; + *ep = NULL; goto done; } - rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id ); + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding entry ID parameter " "for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; - e = NULL; + *ep = NULL; goto done; } @@ -427,12 +269,319 @@ backsql_delete( Operation *op, SlapReply *rs ) SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - e = NULL; + *ep = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_SUCCESS; + *ep = NULL; + +done:; + *sthp = sth; + + return rs->sr_err; +} + +typedef struct backsql_tree_delete_t { + Operation *btd_op; + int btd_rc; + backsql_entryID *btd_eid; +} backsql_tree_delete_t; + +static int +backsql_tree_delete_search_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + backsql_tree_delete_t *btd; + backsql_entryID *eid; + + btd = (backsql_tree_delete_t *)op->o_callback->sc_private; + + if ( !access_allowed( btd->btd_op, rs->sr_entry, + slap_schema.si_ad_entry, NULL, ACL_WDEL, NULL ) + || !access_allowed( btd->btd_op, rs->sr_entry, + slap_schema.si_ad_children, NULL, ACL_WDEL, NULL ) ) + { + btd->btd_rc = LDAP_INSUFFICIENT_ACCESS; + return rs->sr_err = LDAP_UNAVAILABLE; + } + + assert( rs->sr_entry != NULL ); + assert( rs->sr_entry->e_private != NULL ); + + eid = (backsql_entryID *)rs->sr_entry->e_private; + assert( eid->eid_oc != NULL ); + if ( eid->eid_oc == NULL || eid->eid_oc->bom_delete_proc == NULL ) { + btd->btd_rc = LDAP_UNWILLING_TO_PERFORM; + return rs->sr_err = LDAP_UNAVAILABLE; + } + + eid = backsql_entryID_dup( eid, op->o_tmpmemctx ); + eid->eid_next = btd->btd_eid; + btd->btd_eid = eid; + } + + return 0; +} + +static int +backsql_tree_delete( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + SQLHSTMT *sthp ) +{ + Operation op2 = *op; + slap_callback sc = { 0 }; + SlapReply rs2 = { 0 }; + Filter f = { 0 }; + backsql_tree_delete_t btd = { 0 }; + + int rc; + + /* + * - perform an internal subtree search as the rootdn + * - for each entry + * - check access + * - check objectClass and delete method(s) + * - for each entry + * - delete + * - if successful, commit + */ + + op2.o_tag = LDAP_REQ_SEARCH; + op2.o_protocol = LDAP_VERSION3; + + btd.btd_op = op; + sc.sc_private = &btd; + sc.sc_response = backsql_tree_delete_search_cb; + op2.o_callback = ≻ + + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + + op2.o_managedsait = SLAP_CONTROL_CRITICAL; + + op2.ors_scope = LDAP_SCOPE_SUBTREE; + op2.ors_deref = LDAP_DEREF_NEVER; + op2.ors_slimit = SLAP_NO_LIMIT; + op2.ors_tlimit = SLAP_NO_LIMIT; + op2.ors_filter = &f; + f.f_choice = LDAP_FILTER_PRESENT; + f.f_desc = slap_schema.si_ad_objectClass; + BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" ); + op2.ors_attrs = slap_anlist_all_attributes; + op2.ors_attrsonly = 0; + + rc = op->o_bd->be_search( &op2, &rs2 ); + if ( rc != LDAP_SUCCESS ) { + rc = rs->sr_err = btd.btd_rc; + rs->sr_text = "subtree delete not possible"; + send_ldap_result( op, rs ); + goto clean; + } + + for ( ; btd.btd_eid != NULL; + btd.btd_eid = backsql_free_entryID( btd.btd_eid, + 1, op->o_tmpmemctx ) ) + { + Entry *e = (void *)0xbad; + rc = backsql_delete_int( op, rs, dbh, sthp, btd.btd_eid, &e ); + if ( rc != LDAP_SUCCESS ) { + break; + } + } + +clean:; + for ( ; btd.btd_eid != NULL; + btd.btd_eid = backsql_free_entryID( btd.btd_eid, + 1, op->o_tmpmemctx ) ) + ; + + return rc; +} + +int +backsql_delete( Operation *op, SlapReply *rs ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + SQLHDBC dbh = SQL_NULL_HDBC; + SQLHSTMT sth = SQL_NULL_HSTMT; + backsql_oc_map_rec *oc = NULL; + backsql_srch_info bsi = { 0 }; + backsql_entryID e_id = { 0 }; + Entry d = { 0 }, p = { 0 }, *e = NULL; + struct berval pdn = BER_BVNULL; + int manageDSAit = get_manageDSAit( op ); + + Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", + op->o_req_ndn.bv_val, 0, 0 ); + + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + e = NULL; + goto done; + } + + /* + * Get the entry + */ + bsi.bsi_e = &d; + rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, + LDAP_SCOPE_BASE, + (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + break; + + case LDAP_REFERRAL: + if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && + dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) + { + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + break; + } + e = &d; + /* fallthru */ + + default: + Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " + "could not retrieve deleteDN ID - no such entry\n", + 0, 0, 0 ); + if ( !BER_BVISNULL( &d.e_nname ) ) { + /* FIXME: should always be true! */ + e = &d; + + } else { + e = NULL; + } + goto done; + } + + if ( get_assert( op ) && + ( test_filter( op, &d, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = &d; + goto done; + } + + if ( !access_allowed( op, &d, slap_schema.si_ad_entry, + NULL, ACL_WDEL, NULL ) ) + { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "no write access to entry\n", + 0, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + e = &d; + goto done; + } + + rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn ); + switch ( rs->sr_err ) { + case LDAP_COMPARE_FALSE: + rs->sr_err = LDAP_SUCCESS; + break; + + case LDAP_COMPARE_TRUE: +#ifdef SLAP_CONTROL_X_TREE_DELETE + if ( get_treeDelete( op ) ) { + rs->sr_err = LDAP_SUCCESS; + break; + } +#endif /* SLAP_CONTROL_X_TREE_DELETE */ + + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "entry \"%s\" has children\n", + op->o_req_dn.bv_val, 0, 0 ); + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subordinate objects must be deleted first"; + /* fallthru */ + + default: + e = &d; + goto done; + } + + assert( bsi.bsi_base_id.eid_oc != NULL ); + oc = bsi.bsi_base_id.eid_oc; + if ( oc->bom_delete_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "delete procedure is not defined " + "for this objectclass - aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + e = NULL; + goto done; + } + + /* + * Get the parent + */ + e_id = bsi.bsi_base_id; + memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); + if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) { + dnParent( &op->o_req_ndn, &pdn ); + bsi.bsi_e = &p; + rs->sr_err = backsql_init_search( &bsi, &pdn, + LDAP_SCOPE_BASE, + (time_t)(-1), NULL, dbh, op, rs, + slap_anlist_no_attrs, + BACKSQL_ISF_GET_ENTRY ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " + "could not retrieve deleteDN ID " + "- no such entry\n", + 0, 0, 0 ); + e = &p; + goto done; + } + + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); + + /* check parent for "children" acl */ + if ( !access_allowed( op, &p, slap_schema.si_ad_children, + NULL, ACL_WDEL, NULL ) ) + { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "no write access to parent\n", + 0, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + e = &p; + goto done; + + } + } + + e = &d; +#ifdef SLAP_CONTROL_X_TREE_DELETE + if ( get_treeDelete( op ) ) { + backsql_tree_delete( op, rs, dbh, &sth ); + if ( rs->sr_err == LDAP_OTHER || rs->sr_err == LDAP_SUCCESS ) + { + e = NULL; + } + + } else +#endif /* SLAP_CONTROL_X_TREE_DELETE */ + { + backsql_delete_int( op, rs, dbh, &sth, &e_id, &e ); + } /* * Commit only if all operations succeed @@ -472,7 +621,7 @@ done:; Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 ); if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &e_id, 0 ); + (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &d.e_nname ) ) { diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 39122f2c10..78f1da1445 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -36,7 +36,36 @@ struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR ); #endif /* BACKSQL_ARBITRARY_KEY */ backsql_entryID * -backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit ) +backsql_entryID_dup( backsql_entryID *src, void *ctx ) +{ + backsql_entryID *dst; + + if ( src == NULL ) return NULL; + + dst = slap_sl_calloc( 1, sizeof( backsql_entryID ), ctx ); + ber_dupbv_x( &dst->eid_ndn, &src->eid_ndn, ctx ); + if ( src->eid_dn.bv_val == src->eid_ndn.bv_val ) { + dst->eid_dn = dst->eid_ndn; + } else { + ber_dupbv_x( &dst->eid_dn, &src->eid_dn, ctx ); + } + +#ifdef BACKSQL_ARBITRARY_KEY + ber_dupbv_x( &dst->eid_id, &src->eid_id, ctx ); + ber_dupbv_x( &dst->eid_keyval, &src->eid_keyval, ctx ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + dst->eid_id = src->eid_id; + dst->eid_keyval = src->eid_keyval; +#endif /* ! BACKSQL_ARBITRARY_KEY */ + + dst->eid_oc = src->eid_oc; + dst->eid_oc_id = src->eid_oc_id; + + return dst; +} + +backsql_entryID * +backsql_free_entryID( backsql_entryID *id, int freeit, void *ctx ) { backsql_entryID *next; @@ -48,28 +77,28 @@ backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit ) if ( !BER_BVISNULL( &id->eid_dn ) && id->eid_dn.bv_val != id->eid_ndn.bv_val ) { - op->o_tmpfree( id->eid_dn.bv_val, op->o_tmpmemctx ); + slap_sl_free( id->eid_dn.bv_val, ctx ); BER_BVZERO( &id->eid_dn ); } - op->o_tmpfree( id->eid_ndn.bv_val, op->o_tmpmemctx ); + slap_sl_free( id->eid_ndn.bv_val, ctx ); BER_BVZERO( &id->eid_ndn ); } #ifdef BACKSQL_ARBITRARY_KEY if ( !BER_BVISNULL( &id->eid_id ) ) { - op->o_tmpfree( id->eid_id.bv_val, op->o_tmpmemctx ); + slap_sl_free( id->eid_id.bv_val, ctx ); BER_BVZERO( &id->eid_id ); } if ( !BER_BVISNULL( &id->eid_keyval ) ) { - op->o_tmpfree( id->eid_keyval.bv_val, op->o_tmpmemctx ); + slap_sl_free( id->eid_keyval.bv_val, ctx ); BER_BVZERO( &id->eid_keyval ); } #endif /* BACKSQL_ARBITRARY_KEY */ if ( freeit ) { - op->o_tmpfree( id, op->o_tmpmemctx ); + slap_sl_free( id, ctx ); } return next; @@ -291,7 +320,7 @@ backsql_dn2id( ldap_err2string( res ) ); /* cleanup... */ - (void)backsql_free_entryID( op, id, 0 ); + (void)backsql_free_entryID( id, 0, op->o_tmpmemctx ); } if ( dn.bv_val != row.cols[ 3 ] ) { @@ -516,8 +545,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) #endif /* ! BACKSQL_ARBITRARY_KEY */ #ifdef BACKSQL_PRETTY_VALIDATE - validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate; - pretty = at->bam_ad->ad_type->sat_syntax->ssyn_pretty; + validate = at->bam_true_ad->ad_type->sat_syntax->ssyn_validate; + pretty = at->bam_true_ad->ad_type->sat_syntax->ssyn_pretty; if ( validate == NULL && pretty == NULL ) { return 1; @@ -525,8 +554,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) #endif /* BACKSQL_PRETTY_VALIDATE */ #ifdef BACKSQL_COUNTQUERY - if ( at->bam_ad->ad_type->sat_equality ) { - normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize; + if ( at->bam_true_ad->ad_type->sat_equality ) { + normfunc = at->bam_true_ad->ad_type->sat_equality->smr_normalize; } /* Count how many rows will be returned. This avoids memory @@ -583,7 +612,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) return 1; } - attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad ); + attr = attr_find( bsi->bsi_e->e_attrs, at->bam_true_ad ); if ( attr != NULL ) { BerVarray tmp; @@ -615,7 +644,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) append = 1; /* Make space for the array of values */ - attr = attr_alloc( at->bam_ad ); + attr = attr_alloc( at->bam_true_ad ); attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) ); if ( attr->a_vals == NULL ) { Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 ); @@ -735,22 +764,38 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) } #endif /* BACKSQL_TRACE */ - /* - * FIXME: what if a binary - * is fetched? + /* ITS#3386, ITS#3113 - 20070308 + * If a binary is fetched? + * must use the actual size read + * from the database. */ - ber_str2bv( row.cols[ i ], 0, 0, &bv ); + if ( BACKSQL_IS_BINARY( row.col_type[ i ] ) ) { +#ifdef BACKSQL_TRACE + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "column name %s: data is binary; " + "using database size %ld\n", + bsi->bsi_e->e_name.bv_val, + ad->ad_cname.bv_val, + row.value_len[ i ] ); +#endif /* BACKSQL_TRACE */ + bv.bv_val = row.cols[ i ]; + bv.bv_len = row.value_len[ i ]; + + } else { + ber_str2bv( row.cols[ i ], 0, 0, &bv ); + } #ifdef BACKSQL_PRETTY_VALIDATE if ( pretty ) { struct berval pbv; - retval = pretty( at->bam_ad->ad_type->sat_syntax, + retval = pretty( at->bam_true_ad->ad_type->sat_syntax, &bv, &pbv, bsi->bsi_op->o_tmpmemctx ); bv = pbv; } else { - retval = validate( at->bam_ad->ad_type->sat_syntax, + retval = validate( at->bam_true_ad->ad_type->sat_syntax, &bv ); } @@ -776,7 +821,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) #ifndef BACKSQL_COUNTQUERY (void)backsql_entry_addattr( bsi->bsi_e, - at->bam_ad, &bv, + at->bam_true_ad, &bv, bsi->bsi_op->o_tmpmemctx ); #else /* BACKSQL_COUNTQUERY */ @@ -784,8 +829,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) struct berval nbv; retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - at->bam_ad->ad_type->sat_syntax, - at->bam_ad->ad_type->sat_equality, + at->bam_true_ad->ad_type->sat_syntax, + at->bam_true_ad->ad_type->sat_equality, &bv, &nbv, bsi->bsi_op->o_tmpmemctx ); @@ -909,8 +954,11 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) bsi->bsi_e->e_attrs = NULL; bsi->bsi_e->e_private = NULL; - bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private, + if ( eid->eid_oc == NULL ) { + eid->eid_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private, eid->eid_oc_id ); + } + bsi->bsi_oc = eid->eid_oc; bsi->bsi_c_eid = eid; #ifndef BACKSQL_ARBITRARY_KEY @@ -999,12 +1047,13 @@ next:; || an_find( bsi->bsi_attrs, &AllOper ) || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) ) { + ObjectClass *soc = NULL; + if ( BACKSQL_CHECK_SCHEMA( bi ) ) { Attribute *a; const char *text = NULL; char textbuf[ 1024 ]; size_t textlen = sizeof( textbuf ); - ObjectClass *soc = NULL; struct berval bv[ 2 ], *nvals; int rc = LDAP_SUCCESS; @@ -1032,20 +1081,32 @@ next:; } if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) { + if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) { + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " + "computed structuralObjectClass %s " + "does not match objectClass %s associated " + "to entry\n", + bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val, + bsi->bsi_oc->bom_oc->soc_cname.bv_val ); + backsql_entry_clean( op, bsi->bsi_e ); + return rc; + } + Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " "computed structuralObjectClass %s " - "does not match objectClass %s associated " + "is subclass of objectClass %s associated " "to entry\n", bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val, bsi->bsi_oc->bom_oc->soc_cname.bv_val ); - backsql_entry_clean( op, bsi->bsi_e ); - return rc; } + + } else { + soc = bsi->bsi_oc->bom_oc; } rc = attr_merge_normalize_one( bsi->bsi_e, slap_schema.si_ad_structuralObjectClass, - &bsi->bsi_oc->bom_oc->soc_cname, + &soc->soc_cname, bsi->bsi_op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { backsql_entry_clean( op, bsi->bsi_e ); diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c index df67a50006..0f9dc65c22 100644 --- a/servers/slapd/back-sql/init.c +++ b/servers/slapd/back-sql/init.c @@ -27,6 +27,7 @@ #include "ac/string.h" #include "slap.h" +#include "config.h" #include "proto-sql.h" int @@ -37,9 +38,10 @@ sql_back_initialize( LDAP_CONTROL_ASSERT, LDAP_CONTROL_MANAGEDSAIT, LDAP_CONTROL_NOOP, -#if 0 /* SLAP_CONTROL_X_TREE_DELETE */ +#ifdef SLAP_CONTROL_X_TREE_DELETE SLAP_CONTROL_X_TREE_DELETE, #endif /* SLAP_CONTROL_X_TREE_DELETE */ + LDAP_CONTROL_PAGEDRESULTS, NULL }; @@ -75,7 +77,6 @@ sql_back_initialize( bi->bi_entry_release_rw = backsql_entry_release; bi->bi_connection_init = 0; - bi->bi_connection_destroy = backsql_connection_destroy; Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 ); return 0; @@ -92,7 +93,8 @@ backsql_destroy( int backsql_db_init( - BackendDB *bd ) + BackendDB *bd, + ConfigReply *cr ) { backsql_info *bi; int rc = 0; @@ -116,19 +118,16 @@ backsql_db_init( int backsql_db_destroy( - BackendDB *bd ) + BackendDB *bd, + ConfigReply *cr ) { backsql_info *bi = (backsql_info*)bd->be_private; Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 ); - ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex ); backsql_free_db_env( bi ); - ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex ); ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex ); - ldap_pvt_thread_mutex_lock( &bi->sql_schema_mutex ); backsql_destroy_schema_map( bi ); - ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex ); ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex ); if ( bi->sql_dbname ) { @@ -157,6 +156,9 @@ backsql_db_destroy( if ( !BER_BVISNULL( &bi->sql_children_cond ) ) { ch_free( bi->sql_children_cond.bv_val ); } + if ( !BER_BVISNULL( &bi->sql_dn_match_cond ) ) { + ch_free( bi->sql_dn_match_cond.bv_val ); + } if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) { ch_free( bi->sql_subtree_cond.bv_val ); } @@ -216,15 +218,18 @@ backsql_db_destroy( int backsql_db_open( - BackendDB *bd ) + BackendDB *bd, + ConfigReply *cr ) { backsql_info *bi = (backsql_info*)bd->be_private; - SQLHDBC dbh = SQL_NULL_HDBC; struct berbuf bb = BB_NULL; - OperationBuffer opbuf; - Operation* op = (Operation *) &opbuf; - + Connection conn = { 0 }; + OperationBuffer opbuf; + Operation* op; + SQLHDBC dbh = SQL_NULL_HDBC; + void *thrctx = ldap_pvt_thread_pool_context(); + Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): " "testing RDBMS connection\n", 0, 0, 0 ); if ( bi->sql_dbname == NULL ) { @@ -315,18 +320,20 @@ backsql_db_open( }; struct berbuf bb = BB_NULL; + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "subtree search SQL condition not specified " + "(use \"subtree_cond\" directive in slapd.conf); " + "preparing default\n", + 0, 0, 0); + if ( backsql_prepare_pattern( bi->sql_concat_func, values, &concat ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " - "unable to prepare CONCAT pattern", 0, 0, 0 ); + "unable to prepare CONCAT pattern for subtree search", + 0, 0, 0 ); return 1; } - Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " - "subtree search SQL condition not specified " - "(use \"subtree_cond\" directive in slapd.conf)\n", - 0, 0, 0); - if ( bi->sql_upper_func.bv_val ) { /* @@ -358,42 +365,112 @@ backsql_db_open( bi->sql_subtree_cond = bb.bb_val; Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " - "setting \"%s\" as default\n", + "setting \"%s\" as default \"subtree_cond\"\n", bi->sql_subtree_cond.bv_val, 0, 0 ); } if ( bi->sql_children_cond.bv_val == NULL ) { + /* + * Prepare concat function for children search condition + */ + struct berval concat; + struct berval values[] = { + BER_BVC( "'%,'" ), + BER_BVC( "?" ), + BER_BVNULL + }; struct berbuf bb = BB_NULL; + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "children search SQL condition not specified " + "(use \"children_cond\" directive in slapd.conf); " + "preparing default\n", + 0, 0, 0); + + if ( backsql_prepare_pattern( bi->sql_concat_func, values, + &concat ) ) { + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "unable to prepare CONCAT pattern for children search", 0, 0, 0 ); + return 1; + } + if ( bi->sql_upper_func.bv_val ) { /* * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?)) */ - backsql_strfcat_x( &bb, NULL, "blbl", + backsql_strfcat_x( &bb, NULL, "blbbb", + &bi->sql_upper_func, + (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ), + "(ldap_entries.dn) LIKE ", + &bi->sql_upper_func_open, + &concat, + &bi->sql_upper_func_close ); + + } else { + + /* + * ldap_entries.dn LIKE CONCAT('%,',?) + */ + + backsql_strfcat_x( &bb, NULL, "lb", + (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ), + "ldap_entries.dn LIKE ", + &concat ); + } + + ch_free( concat.bv_val ); + + bi->sql_children_cond = bb.bb_val; + + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "setting \"%s\" as default \"children_cond\"\n", + bi->sql_children_cond.bv_val, 0, 0 ); + } + + if ( bi->sql_dn_match_cond.bv_val == NULL ) { + /* + * Prepare concat function for dn match search condition + */ + struct berbuf bb = BB_NULL; + + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "DN match search SQL condition not specified " + "(use \"dn_match_cond\" directive in slapd.conf); " + "preparing default\n", + 0, 0, 0); + + if ( bi->sql_upper_func.bv_val ) { + + /* + * UPPER(ldap_entries.dn)=? + */ + + backsql_strfcat_x( &bb, NULL, "blbcb", &bi->sql_upper_func, (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ), "(ldap_entries.dn)=", - &bi->sql_upper_func, - (ber_len_t)STRLENOF( "(?)" ), "(?)" ); + &bi->sql_upper_func_open, + '?', + &bi->sql_upper_func_close ); } else { /* - * ldap_entries.dn LIKE CONCAT('%,',?) + * ldap_entries.dn=? */ backsql_strfcat_x( &bb, NULL, "l", (ber_len_t)STRLENOF( "ldap_entries.dn=?" ), - "ldap_entries.dn=?"); + "ldap_entries.dn=?" ); } - bi->sql_children_cond = bb.bb_val; + bi->sql_dn_match_cond = bb.bb_val; Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " - "setting \"%s\" as default\n", - bi->sql_children_cond.bv_val, 0, 0 ); + "setting \"%s\" as default \"dn_match_cond\"\n", + bi->sql_dn_match_cond.bv_val, 0, 0 ); } if ( bi->sql_oc_query == NULL ) { @@ -469,16 +546,20 @@ backsql_db_open( } /* This should just be to force schema loading */ - op->o_hdr = (Opheader *)&op[ 1 ]; - op->o_connid = (unsigned long)(-1); + connection_fake_init( &conn, &opbuf, thrctx ); + op = &opbuf.ob_op; op->o_bd = bd; if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " "connection failed, exiting\n", 0, 0, 0 ); return 1; } - - if ( backsql_free_db_conn( op ) != SQL_SUCCESS ) { + if ( backsql_load_schema_map( bi, dbh ) != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " + "schema mapping failed, exiting\n", 0, 0, 0 ); + return 1; + } + if ( backsql_free_db_conn( op, dbh ) != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): " "connection free failed\n", 0, 0, 0 ); } @@ -522,7 +603,7 @@ backsql_db_open( } /* - * Prepare children ID selection query + * Prepare children count query */ BER_BVZERO( &bb.bb_val ); bb.bb_len = 0; @@ -531,7 +612,7 @@ backsql_db_open( "FROM ldap_entries,ldap_entries ", &bi->sql_aliasing, "subordinates " "WHERE subordinates.parent=ldap_entries.id AND ", - &bi->sql_children_cond ); + &bi->sql_dn_match_cond ); bi->sql_has_children_query = bb.bb_val.bv_val; /* @@ -563,7 +644,8 @@ backsql_db_open( int backsql_db_close( - BackendDB *bd ) + BackendDB *bd, + ConfigReply *cr ) { backsql_info *bi = (backsql_info*)bd->be_private; @@ -576,23 +658,6 @@ backsql_db_close( return 0; } -int -backsql_connection_destroy( Backend *bd, Connection *c ) -{ - OperationBuffer opbuf; - Operation* op = (Operation *) &opbuf; - - op->o_hdr = (Opheader *)&op[ 1 ]; - op->o_connid = c->c_connid; - op->o_bd = bd; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_connection_destroy()\n", 0, 0, 0 ); - backsql_free_db_conn( op ); - Debug( LDAP_DEBUG_TRACE, "<==backsql_connection_destroy()\n", 0, 0, 0 ); - - return 0; -} - #if SLAPD_SQL == SLAPD_MOD_DYNAMIC /* conditionally define the init_module() function */ diff --git a/servers/slapd/back-sql/modify.c b/servers/slapd/back-sql/modify.c index 4ee11dbd58..ca1fc3ba79 100644 --- a/servers/slapd/back-sql/modify.c +++ b/servers/slapd/back-sql/modify.c @@ -67,7 +67,7 @@ backsql_modify( Operation *op, SlapReply *rs ) LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, - ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; @@ -124,17 +124,17 @@ backsql_modify( Operation *op, SlapReply *rs ) slap_mods_opattrs( op, &op->orm_modlist, 1 ); - oc = backsql_id2oc( bi, bsi.bsi_base_id.eid_oc_id ); - assert( oc != NULL ); + assert( bsi.bsi_base_id.eid_oc != NULL ); + oc = bsi.bsi_base_id.eid_oc; - if ( !acl_check_modlist( op, &m, op->oq_modify.rs_modlist ) ) { + if ( !acl_check_modlist( op, &m, op->orm_modlist ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; e = &m; goto done; } rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, - &bsi.bsi_base_id, op->oq_modify.rs_modlist ); + &bsi.bsi_base_id, op->orm_modlist ); if ( rs->sr_err != LDAP_SUCCESS ) { e = &m; goto do_transact; @@ -197,7 +197,7 @@ done:; slap_graduate_commit_csn( op ); if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &m.e_nname ) ) { diff --git a/servers/slapd/back-sql/modrdn.c b/servers/slapd/back-sql/modrdn.c index 4634078fdd..1e6805a7fd 100644 --- a/servers/slapd/back-sql/modrdn.c +++ b/servers/slapd/back-sql/modrdn.c @@ -72,7 +72,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, - ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; @@ -164,6 +164,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) */ bsi.bsi_e = &p; e_id = bsi.bsi_base_id; + memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); rs->sr_err = backsql_init_search( &bsi, &pndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, @@ -197,7 +198,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) } if ( newSuperior ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); /* * namingContext "" is not supported @@ -259,6 +260,8 @@ backsql_modrdn( Operation *op, SlapReply *rs ) new_npdn = &pndn; } + memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); + if ( newSuperior && dn_match( &pndn, new_npdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "newSuperior is equal to old parent - ignored\n", @@ -395,7 +398,8 @@ backsql_modrdn( Operation *op, SlapReply *rs ) slap_mods_opattrs( op, &op->orr_modlist, 1 ); - oc = backsql_id2oc( bi, e_id.eid_oc_id ); + assert( e_id.eid_oc != NULL ); + oc = e_id.eid_oc; rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist ); slap_graduate_commit_csn( op ); if ( rs->sr_err != LDAP_SUCCESS ) { @@ -407,7 +411,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; backsql_entry_clean( op, &r ); - (void)backsql_free_entryID( op, &e_id, 0 ); + (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); bsi.bsi_e = &r; rs->sr_err = backsql_init_search( &bsi, &new_ndn, @@ -510,11 +514,11 @@ done:; } if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &e_id, 0 ); + (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &n_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &n_id, 0 ); + (void)backsql_free_entryID( &n_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &r.e_nname ) ) { diff --git a/servers/slapd/back-sql/operational.c b/servers/slapd/back-sql/operational.c index 60252f6d49..f6fe6aea4f 100644 --- a/servers/slapd/back-sql/operational.c +++ b/servers/slapd/back-sql/operational.c @@ -189,7 +189,7 @@ backsql_operational( *ap = backsql_operational_entryUUID( bi, &bsi.bsi_base_id ); - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); if ( bsi.bsi_attrs != NULL ) { op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); diff --git a/servers/slapd/back-sql/proto-sql.h b/servers/slapd/back-sql/proto-sql.h index 78b9251556..3af14d5ee0 100644 --- a/servers/slapd/back-sql/proto-sql.h +++ b/servers/slapd/back-sql/proto-sql.h @@ -111,24 +111,32 @@ extern struct berval backsql_baseObject_bv; #endif /* BACKSQL_ARBITRARY_KEY */ /* stores in *id the ID in table ldap_entries corresponding to DN, if any */ -int backsql_dn2id( Operation *op, SlapReply *rs, SQLHDBC dbh, +extern int +backsql_dn2id( Operation *op, SlapReply *rs, SQLHDBC dbh, struct berval *ndn, backsql_entryID *id, int matched, int muck ); /* stores in *nchildren the count of children for an entry */ -int backsql_count_children( Operation *op, SQLHDBC dbh, +extern int +backsql_count_children( Operation *op, SQLHDBC dbh, struct berval *dn, unsigned long *nchildren ); /* returns LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE if the entry corresponding * to DN has/has not children */ -int backsql_has_children( Operation *op, SQLHDBC dbh, struct berval *dn ); +extern int +backsql_has_children( Operation *op, SQLHDBC dbh, struct berval *dn ); -/* frees *id and returns next in list */ -backsql_entryID *backsql_free_entryID( Operation *op, backsql_entryID *id, - int freeit ); +/* free *id and return next in list */ +extern backsql_entryID * +backsql_free_entryID( backsql_entryID *id, int freeit, void *ctx ); -/* turns an ID into an entry */ -int backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *id ); +/* turn an ID into an entry */ +extern int +backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *id ); + +/* duplicate an entryID */ +extern backsql_entryID * +backsql_entryID_dup( backsql_entryID *eid, void *ctx ); /* * operational.c @@ -219,9 +227,9 @@ int backsql_init_db_env( backsql_info *si ); int backsql_free_db_env( backsql_info *si ); -int backsql_get_db_conn( Operation *op, SQLHDBC *dbh ); +int backsql_get_db_conn( Operation *op, SQLHDBC *dbh ); -int backsql_free_db_conn( Operation *op ); +int backsql_free_db_conn( Operation *op, SQLHDBC dbh ); /* * util.c diff --git a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_create.sql b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_create.sql index 3c6b71e8b0..b35261b468 100644 --- a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_create.sql +++ b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_create.sql @@ -32,7 +32,12 @@ CREATE TABLE phones ( pers_id int NOT NULL ); - +drop table if exists certs; +CREATE TABLE certs ( + id int NOT NULL , + cert LONGBLOB NOT NULL, + pers_id int NOT NULL +); ALTER TABLE authors_docs ADD CONSTRAINT PK_authors_docs PRIMARY KEY @@ -66,6 +71,12 @@ ALTER TABLE phones ADD id ); +ALTER TABLE certs ADD + CONSTRAINT PK_certs PRIMARY KEY + ( + id + ); + drop table if exists referrals; CREATE TABLE referrals ( id int NOT NULL, diff --git a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_data.sql b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_data.sql index 7bef37495a..0ccbfb76a2 100644 --- a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_data.sql +++ b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_data.sql @@ -16,3 +16,6 @@ insert into authors_docs (pers_id,doc_id) values (1,2); insert into authors_docs (pers_id,doc_id) values (2,1); insert into referrals (id,name,url) values (1,'Referral','ldap://localhost:9012/'); + +insert into certs (id,cert,pers_id) values (1,UNHEX('3082036b308202d4a003020102020102300d06092a864886f70d01010405003077310b3009060355040613025553311330110603550408130a43616c69666f726e6961311f301d060355040a13164f70656e4c444150204578616d706c652c204c74642e311330110603550403130a4578616d706c65204341311d301b06092a864886f70d010901160e6361406578616d706c652e636f6d301e170d3033313031373136333331395a170d3034313031363136333331395a307e310b3009060355040613025553311330110603550408130a43616c69666f726e6961311f301d060355040a13164f70656e4c444150204578616d706c652c204c74642e311830160603550403130f557273756c612048616d7073746572311f301d06092a864886f70d01090116107568616d406578616d706c652e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100eec60a7910b57d2e687158ca55eea738d36f10413dfecf31435e1aeeb9713b8e2da7dd2dde6bc6cec03b4987eaa7b037b9eb50e11c71e58088cc282883122cd8329c6f24f6045e6be9d21b9190c8292998267a5f7905292de936262747ab4b76a88a63872c41629a69d32e894d44c896a8d06fab0a1bc7de343c6c1458478f290203010001a381ff3081fc30090603551d1304023000302c06096086480186f842010d041f161d4f70656e53534c2047656e657261746564204365727469666963617465301d0603551d0e04160414a323de136c19ae0c479450e882dfb10ad147f45e3081a10603551d2304819930819680144b6f211a3624d290f943b053472d7de1c0e69823a17ba4793077310b3009060355040613025553311330110603550408130a43616c69666f726e6961311f301d060355040a13164f70656e4c444150204578616d706c652c204c74642e311330110603550403130a4578616d706c65204341311d301b06092a864886f70d010901160e6361406578616d706c652e636f6d820100300d06092a864886f70d010104050003818100881470045bdce95660d6e6af59e6a844aec4b9f5eaea88d4eb7a5a47080afa64750f81a3e47d00fd39c69a17a1c66d29d36f06edc537107f8c592239c2d4da55fb3f1d488e7b2387ad2a551cbd1ceb070ae9e020a9467275cb28798abb4cbfff98ddb3f1e7689b067072392511bb08125b5bec2bc207b7b6b275c47248f29acd'),3); + diff --git a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_metadata.sql b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_metadata.sql index 1606600fe9..d7e88e40fa 100644 --- a/servers/slapd/back-sql/rdbms_depend/mysql/testdb_metadata.sql +++ b/servers/slapd/back-sql/rdbms_depend/mysql/testdb_metadata.sql @@ -80,6 +80,10 @@ values (13,4,'ou','referrals.name','referrals',NULL,NULL,NULL,3,0); insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (14,4,'ref','referrals.url','referrals',NULL,NULL,NULL,3,0); +insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) +values (15,1,'userCertificate','certs.cert','persons,certs', + 'certs.pers_id=persons.id',NULL,NULL,3,0); + -- entries mapping: each entry must appear in this table, with a unique DN rooted at the database naming context -- id a unique number > 0 identifying the entry -- dn the DN of the entry, in "pretty" form @@ -113,6 +117,9 @@ values (7,'ou=Referral,dc=example,dc=com',4,1,1); insert into ldap_entry_objclasses (entry_id,oc_name) values (1,'dcObject'); +insert into ldap_entry_objclasses (entry_id,oc_name) +values (4,'pkiUser'); + insert into ldap_entry_objclasses (entry_id,oc_name) values (7,'extensibleObject'); diff --git a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_create.sql b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_create.sql index 0142dd9b15..e1c57e785c 100644 --- a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_create.sql +++ b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_create.sql @@ -37,6 +37,14 @@ create table phones ( pers_id int not null ); +drop table certs; +drop sequence certs_id_seq; +CREATE TABLE certs ( + id int not null primary key, + cert bytea not null, + pers_id int not null +); + drop table referrals; drop sequence referrals_id_seq; create table referrals ( diff --git a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_data.sql b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_data.sql index 7bef37495a..0e661d4ccc 100644 --- a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_data.sql +++ b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_data.sql @@ -16,3 +16,6 @@ insert into authors_docs (pers_id,doc_id) values (1,2); insert into authors_docs (pers_id,doc_id) values (2,1); insert into referrals (id,name,url) values (1,'Referral','ldap://localhost:9012/'); + +insert into certs (id,cert,pers_id) values (1,decode('MIIDazCCAtSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwgTHRkLjETMBEGA1UEAxMKRXhhbXBsZSBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb20wHhcNMDMxMDE3MTYzMzE5WhcNMDQxMDE2MTYzMzE5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEfMB0GA1UEChMWT3BlbkxEQVAgRXhhbXBsZSwgTHRkLjEYMBYGA1UEAxMPVXJzdWxhIEhhbXBzdGVyMR8wHQYJKoZIhvcNAQkBFhB1aGFtQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDuxgp5ELV9LmhxWMpV7qc4028QQT3+zzFDXhruuXE7ji2n3S3ea8bOwDtJh+qnsDe561DhHHHlgIjMKCiDEizYMpxvJPYEXmvp0huRkMgpKZgmel95BSkt6TYmJ0erS3aoimOHLEFimmnTLolNRMiWqNBvqwobx940PGwUWEePKQIDAQABo4H/MIH8MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSjI94TbBmuDEeUUOiC37EK0Uf0XjCBoQYDVR0jBIGZMIGWgBRLbyEaNiTSkPlDsFNHLX3hwOaYI6F7pHkwdzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExHzAdBgNVBAoTFk9wZW5MREFQIEV4YW1wbGUsIEx0ZC4xEzARBgNVBAMTCkV4YW1wbGUgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAIgUcARb3OlWYNbmr1nmqESuxLn16uqI1Ot6WkcICvpkdQ+Bo+R9AP05xpoXocZtKdNvBu3FNxB/jFkiOcLU2lX7Px1Ijnsjh60qVRy9HOsHCungIKlGcnXLKHmKu0y//5jds/HnaJsGcHI5JRG7CBJbW+wrwge3trJ1xHJI8prN','base64'),3); + diff --git a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_metadata.sql b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_metadata.sql index df4a79cfde..d645cf298e 100644 --- a/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_metadata.sql +++ b/servers/slapd/back-sql/rdbms_depend/pgsql/testdb_metadata.sql @@ -55,6 +55,8 @@ insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where, insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (14,4,'ref','referrals.url','referrals',NULL,'UPDATE referrals SET url=? WHERE id=?','SELECT 1 FROM referrals WHERE url=? and id=? and 1=0',3,0); +insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (15,1,'userCertificate','certs.cert','persons,certs','certs.pers_id=persons.id',NULL,NULL,3,0); + -- entries mapping: each entry must appear in this table, with a unique DN rooted at the database naming context -- id a unique number > 0 identifying the entry -- dn the DN of the entry, in "pretty" form @@ -80,6 +82,8 @@ insert into ldap_entries (id,dn,oc_map_id,parent,keyval) values (7,'ou=Referral, -- oc_name the name of the objectClass; it MUST match the name of an objectClass that is loaded in slapd's schema insert into ldap_entry_objclasses (entry_id,oc_name) values (1,'dcObject'); +insert into ldap_entry_objclasses (entry_id,oc_name) values (4,'pkiUser'); + insert into ldap_entry_objclasses (entry_id,oc_name) values (7,'extensibleObject'); -- procedures diff --git a/servers/slapd/back-sql/schema-map.c b/servers/slapd/back-sql/schema-map.c index d64d5e937e..5dbe2ff084 100644 --- a/servers/slapd/back-sql/schema-map.c +++ b/servers/slapd/back-sql/schema-map.c @@ -74,6 +74,14 @@ backsql_cmp_attr( const void *v_m1, const void *v_m2 ) const backsql_at_map_rec *m1 = v_m1, *m2 = v_m2; + if ( slap_ad_is_binary( m1->bam_ad ) || slap_ad_is_binary( m2->bam_ad ) ) { +#ifdef BACKSQL_USE_PTR_CMP + return SLAP_PTRCMP( m1->bam_ad->ad_type, m2->bam_ad->ad_type ); +#else /* ! BACKSQL_USE_PTR_CMP */ + return ber_bvcmp( &m1->bam_ad->ad_type->sat_cname, &m2->bam_ad->ad_type->sat_cname ); +#endif /* ! BACKSQL_USE_PTR_CMP */ + } + #ifdef BACKSQL_USE_PTR_CMP return SLAP_PTRCMP( m1->bam_ad, m2->bam_ad ); #else /* ! BACKSQL_USE_PTR_CMP */ @@ -87,12 +95,26 @@ backsql_dup_attr( void *v_m1, void *v_m2 ) backsql_at_map_rec *m1 = v_m1, *m2 = v_m2; - assert( m1->bam_ad == m2->bam_ad ); + if ( slap_ad_is_binary( m1->bam_ad ) || slap_ad_is_binary( m2->bam_ad ) ) { +#ifdef BACKSQL_USE_PTR_CMP + assert( m1->bam_ad->ad_type == m2->bam_ad->ad_type ); +#else /* ! BACKSQL_USE_PTR_CMP */ + assert( ber_bvcmp( &m1->bam_ad->ad_type->sat_cname, &m2->bam_ad->ad_type->sat_cname ) == 0 ); +#endif /* ! BACKSQL_USE_PTR_CMP */ + + } else { +#ifdef BACKSQL_USE_PTR_CMP + assert( m1->bam_ad == m2->bam_ad ); +#else /* ! BACKSQL_USE_PTR_CMP */ + assert( ber_bvcmp( &m1->bam_ad->ad_cname, &m2->bam_ad->ad_cname ) == 0 ); +#endif /* ! BACKSQL_USE_PTR_CMP */ + } /* duplicate definitions of attributeTypes are appended; * this allows to define multiple rules for the same * attributeType. Use with care! */ for ( ; m1->bam_next ; m1 = m1->bam_next ); + m1->bam_next = m2; m2->bam_next = NULL; @@ -178,6 +200,7 @@ backsql_add_sysmaps( backsql_info *bi, backsql_oc_map_rec *oc_map ) at_map = (backsql_at_map_rec *)ch_calloc(1, sizeof( backsql_at_map_rec ) ); at_map->bam_ad = slap_schema.si_ad_objectClass; + at_map->bam_true_ad = slap_schema.si_ad_objectClass; ber_str2bv( "ldap_entry_objclasses.oc_name", 0, 1, &at_map->bam_sel_expr ); ber_str2bv( "ldap_entry_objclasses,ldap_entries", 0, 1, @@ -350,6 +373,26 @@ backsql_oc_get_attr_mapping( void *v_oc, void *v_bas ) at_map = (backsql_at_map_rec *)ch_calloc( 1, sizeof( backsql_at_map_rec ) ); at_map->bam_ad = ad; + at_map->bam_true_ad = ad; + if ( slap_syntax_is_binary( ad->ad_type->sat_syntax ) + && !slap_ad_is_binary( ad ) ) + { + char buf[ BUFSIZ ]; + struct berval bv; + const char *text = NULL; + + bv.bv_val = buf; + bv.bv_len = snprintf( buf, sizeof( buf ), "%s;binary", + ad->ad_cname.bv_val ); + at_map->bam_true_ad = NULL; + bas->bas_rc = slap_bv2ad( &bv, &at_map->bam_true_ad, &text ); + if ( bas->bas_rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): " + "unable to fetch attribute \"%s\": %s (%d)\n", + buf, text, rc ); + return BACKSQL_AVL_STOP; + } + } ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr ); if ( at_row.value_len[ 8 ] < 0 ) { @@ -717,7 +760,7 @@ backsql_id2oc( backsql_info *bi, unsigned long id ) backsql_at_map_rec * backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad ) { - backsql_at_map_rec tmp, *res; + backsql_at_map_rec tmp = { 0 }, *res; #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): " diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index b9d9365034..e0777f3e82 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -42,6 +42,23 @@ static int backsql_process_filter_like( backsql_srch_info *bsi, static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ); +/* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of + the state of paged results. The ldap_entries.id and oc_map_id values of the + last entry returned are used as the cookie, so 6 bits are used for the OC id + and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more + than 63, you will need to steal more bits from ldap_entries ID number and + put them into the OC ID part of the cookie. */ +#define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F)) +#define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6) +#define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F) + +static int parse_paged_cookie( Operation *op, SlapReply *rs ); + +static void send_paged_response( + Operation *op, + SlapReply *rs, + ID *lastid ); + static int backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ) { @@ -62,6 +79,11 @@ backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ) return 1; } + /* strip ';binary' */ + if ( slap_ad_is_binary( ad ) ) { + ad = ad->ad_type->sat_ad; + } + for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) { an = &bsi->bsi_attrs[ n_attrs ]; @@ -317,6 +339,17 @@ backsql_init_search( rs->sr_err = rc; } } + + if ( gotit && BACKSQL_IS_GET_OC( flags ) ) { + bsi->bsi_base_id.eid_oc = backsql_id2oc( bi, + bsi->bsi_base_id.eid_oc_id ); + if ( bsi->bsi_base_id.eid_oc == NULL ) { + /* error? */ + backsql_free_entryID( &bsi->bsi_base_id, 1, + op->o_tmpmemctx ); + rc = rs->sr_err = LDAP_OTHER; + } + } } bsi->bsi_status = rc; @@ -1490,6 +1523,7 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) (ber_len_t)STRLENOF( "9=9"), "9=9"); } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) { + /* This should always be true... */ backsql_strfcat_x( &bsi->bsi_join_where, bsi->bsi_op->o_tmpmemctx, "b", @@ -1517,6 +1551,30 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) assert( 0 ); } + /* If paged results are in effect, ignore low ldap_entries.id numbers */ + if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) { + unsigned long lowid = 0; + + /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */ + if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) ) + { + lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ); + } + + if ( lowid ) { + char lowidstring[48]; + int lowidlen; + + lowidlen = snprintf( lowidstring, sizeof( lowidstring ), + " AND ldap_entries.id>%lu", lowid ); + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", + (ber_len_t)lowidlen, + lowidstring ); + } + } + rc = backsql_process_filter( bsi, bsi->bsi_filter ); if ( rc > 0 ) { struct berbuf bb = BB_NULL; @@ -1596,6 +1654,14 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) return BACKSQL_AVL_STOP; } + /* If paged results have already completed this objectClass, skip it */ + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) ) + { + return BACKSQL_AVL_CONTINUE; + } + } + if ( bsi->bsi_n_candidates == -1 ) { Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " "unchecked limit has been overcome\n", 0, 0, 0 ); @@ -1860,6 +1926,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) goto cleanup; } #endif /* ! BACKSQL_ARBITRARY_KEY */ + c_id->eid_oc = bsi->bsi_oc; c_id->eid_oc_id = bsi->bsi_oc->bom_id; c_id->eid_dn = pdn; @@ -1921,6 +1988,7 @@ backsql_search( Operation *op, SlapReply *rs ) backsql_srch_info bsi = { 0 }; backsql_entryID *eid = NULL; struct berval nbase = BER_BVNULL; + unsigned long lastid = 0; Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): " "base=\"%s\", filter=\"%s\", scope=%d,", @@ -2057,6 +2125,15 @@ backsql_search( Operation *op, SlapReply *rs ) ( op->ors_limit->lms_s_unchecked == -1 ? -2 : ( op->ors_limit->lms_s_unchecked ) ) ); + /* If paged results are in effect, check the paging cookie */ + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { + rs->sr_err = parse_paged_cookie( op, rs ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto done; + } + } + switch ( bsi.bsi_scope ) { case LDAP_SCOPE_BASE: case BACKSQL_SCOPE_BASE_LIKE: @@ -2084,9 +2161,9 @@ backsql_search( Operation *op, SlapReply *rs ) /* * for each objectclass we try to construct query which gets IDs * of entries matching LDAP query filter and scope (or at least - * candidates), and get the IDs + * candidates), and get the IDs. Do this in ID order for paging. */ - avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates, + avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates, &bsi, BACKSQL_AVL_STOP, AVL_INORDER ); /* check for abandon */ @@ -2112,9 +2189,9 @@ backsql_search( Operation *op, SlapReply *rs ) * and then send to client; don't free entry_id if baseObject... */ for ( eid = bsi.bsi_id_list; - eid != NULL; - eid = backsql_free_entryID( op, - eid, eid == &bsi.bsi_base_id ? 0 : 1 ) ) + eid != NULL; + eid = backsql_free_entryID( + eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) { int rc; Attribute *a_hasSubordinate = NULL, @@ -2179,7 +2256,6 @@ backsql_search( Operation *op, SlapReply *rs ) case LDAP_SCOPE_SUBTREE: /* FIXME: this should never fail... */ if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) { - assert( 0 ); goto next_entry2; } break; @@ -2264,6 +2340,9 @@ backsql_search( Operation *op, SlapReply *rs ) rs->sr_ref = NULL; rs->sr_matched = NULL; rs->sr_entry = NULL; + if ( rs->sr_err == LDAP_REFERRAL ) { + rs->sr_err = LDAP_SUCCESS; + } goto next_entry; } @@ -2330,12 +2409,24 @@ backsql_search( Operation *op, SlapReply *rs ) if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { + /* If paged results are in effect, see if the page limit was exceeded */ + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) + { + e = NULL; + send_paged_response( op, rs, &lastid ); + goto done; + } + lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id ); + } rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_entry = e; + e->e_private = (void *)eid; rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0; /* FIXME: need the whole entry (ITS#3480) */ rs->sr_err = send_search_entry( op, rs ); + e->e_private = NULL; rs->sr_entry = NULL; rs->sr_attrs = NULL; rs->sr_operational_attrs = NULL; @@ -2375,13 +2466,17 @@ end_of_search:; send_results:; if ( rs->sr_err != SLAPD_ABANDON ) { - send_ldap_result( op, rs ); + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + send_paged_response( op, rs, NULL ); + } else { + send_ldap_result( op, rs ); + } } /* cleanup in case of abandon */ for ( ; eid != NULL; - eid = backsql_free_entryID( op, - eid, eid == &bsi.bsi_base_id ? 0 : 1 ) ) + eid = backsql_free_entryID( + eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) ; backsql_entry_clean( op, &base_entry ); @@ -2402,7 +2497,7 @@ send_results:; slap_callback cb = { 0 }; op2.o_tag = LDAP_REQ_ADD; - op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 ); + op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 ); op2.ora_e = e; op2.o_callback = &cb; @@ -2419,7 +2514,7 @@ send_results:; #endif /* BACKSQL_SYNCPROV */ done:; - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); if ( bsi.bsi_attrs != NULL ) { op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); @@ -2462,8 +2557,8 @@ backsql_entry_get( *ent = NULL; rc = backsql_get_db_conn( op, &dbh ); - if ( !dbh ) { - return LDAP_OTHER; + if ( rc != LDAP_SUCCESS ) { + return rc; } if ( at ) { @@ -2481,7 +2576,7 @@ backsql_entry_get( BACKSQL_ISF_GET_ENTRY ); if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( rc == LDAP_SUCCESS ) { @@ -2563,7 +2658,164 @@ backsql_entry_release( { backsql_entry_clean( op, e ); - ch_free( e ); + entry_free( e ); return 0; } + + +/* This function is copied verbatim from back-bdb/search.c */ +static int +parse_paged_cookie( Operation *op, SlapReply *rs ) +{ + LDAPControl **c; + int rc = LDAP_SUCCESS; + ber_tag_t tag; + ber_int_t size; + BerElement *ber; + struct berval cookie = BER_BVNULL; + PagedResultsState *ps = op->o_pagedresults_state; + + /* this function must be invoked only if the pagedResults + * control has been detected, parsed and partially checked + * by the frontend */ + assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); + + /* look for the appropriate ctrl structure */ + for ( c = op->o_ctrls; c[0] != NULL; c++ ) { + if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) + { + break; + } + } + + if ( c[0] == NULL ) { + rs->sr_text = "missing pagedResults control"; + return LDAP_PROTOCOL_ERROR; + } + + /* Tested by frontend */ + assert( c[0]->ldctl_value.bv_len > 0 ); + + /* Parse the control value + * realSearchControlValue ::= SEQUENCE { + * size INTEGER (0..maxInt), + * -- requested page size from client + * -- result set size estimate from server + * cookie OCTET STRING + * } + */ + ber = ber_init( &c[0]->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_scanf( ber, "{im}", &size, &cookie ); + + /* Tested by frontend */ + assert( tag != LBER_ERROR ); + assert( size >= 0 ); + + /* cookie decoding/checks deferred to backend... */ + if ( cookie.bv_len ) { + PagedResultsCookie reqcookie; + if( cookie.bv_len != sizeof( reqcookie ) ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + + if ( reqcookie > ps->ps_cookie ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + + } else if ( reqcookie < ps->ps_cookie ) { + rs->sr_text = "paged results cookie is invalid or old"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + } else { + /* Initial request. Initialize state. */ +#if 0 + if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { + /* There's another pagedResults control on the + * same connection; reject new pagedResults controls + * (allowed by RFC2696) */ + rs->sr_text = "paged results cookie unavailable; try later"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } +#endif + ps->ps_cookie = 0; + ps->ps_count = 0; + } + +done:; + (void)ber_free( ber, 1 ); + + return rc; +} + +/* This function is copied nearly verbatim from back-bdb/search.c */ +static void +send_paged_response( + Operation *op, + SlapReply *rs, + unsigned long *lastid ) +{ + LDAPControl ctrl, *ctrls[2]; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + PagedResultsCookie respcookie; + struct berval cookie; + + Debug(LDAP_DEBUG_ARGS, + "send_paged_response: lastid=0x%08lx nentries=%d\n", + lastid ? *lastid : 0, rs->sr_nentries, NULL ); + + BER_BVZERO( &ctrl.ldctl_value ); + ctrls[0] = &ctrl; + ctrls[1] = NULL; + + ber_init2( ber, NULL, LBER_USE_DER ); + + if ( lastid ) { + respcookie = ( PagedResultsCookie )(*lastid); + cookie.bv_len = sizeof( respcookie ); + cookie.bv_val = (char *)&respcookie; + + } else { + respcookie = ( PagedResultsCookie )0; + BER_BVSTR( &cookie, "" ); + } + + op->o_conn->c_pagedresults_state.ps_cookie = respcookie; + op->o_conn->c_pagedresults_state.ps_count = + ((PagedResultsState *)op->o_pagedresults_state)->ps_count + + rs->sr_nentries; + + /* return size of 0 -- no estimate */ + ber_printf( ber, "{iO}", 0, &cookie ); + + if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { + goto done; + } + + ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; + ctrls[0]->ldctl_iscritical = 0; + + rs->sr_ctrls = ctrls; + rs->sr_err = LDAP_SUCCESS; + send_ldap_result( op, rs ); + rs->sr_ctrls = NULL; + +done: + (void) ber_free_buf( ber ); +} diff --git a/servers/slapd/back-sql/sql-wrap.c b/servers/slapd/back-sql/sql-wrap.c index d01d9cbb31..5e40dc2a7b 100644 --- a/servers/slapd/back-sql/sql-wrap.c +++ b/servers/slapd/back-sql/sql-wrap.c @@ -32,11 +32,6 @@ #define MAX_ATTR_LEN 16384 -typedef struct backsql_db_conn { - unsigned long ldap_cid; - SQLHDBC dbh; -} backsql_db_conn; - void backsql_PrintErrors( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT sth, int rc ) { @@ -132,10 +127,6 @@ RETCODE backsql_BindRowAsStrings_x( SQLHSTMT sth, BACKSQL_ROW_NTS *row, void *ctx ) { RETCODE rc; - SQLCHAR colname[ 64 ]; - SQLSMALLINT name_len, col_type, col_scale, col_null; - UDWORD col_prec; - int i; if ( row == NULL ) { return SQL_ERROR; @@ -155,6 +146,11 @@ backsql_BindRowAsStrings_x( SQLHSTMT sth, BACKSQL_ROW_NTS *row, void *ctx ) backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC, sth, rc ); } else { + SQLCHAR colname[ 64 ]; + SQLSMALLINT name_len, col_type, col_scale, col_null; + UDWORD col_prec; + int i; + #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "ncols=%d\n", (int)row->ncols, 0, 0 ); @@ -162,58 +158,115 @@ backsql_BindRowAsStrings_x( SQLHSTMT sth, BACKSQL_ROW_NTS *row, void *ctx ) row->col_names = (BerVarray)ber_memcalloc_x( row->ncols + 1, sizeof( struct berval ), ctx ); - if ( !row->col_names ) goto nomem3; - row->cols = (char **)ber_memcalloc_x( row->ncols + 1, - sizeof( char * ), ctx ); - if ( !row->cols ) goto nomem2; + if ( row->col_names == NULL ) { + goto nomem; + } + row->col_prec = (UDWORD *)ber_memcalloc_x( row->ncols, sizeof( UDWORD ), ctx ); - if ( !row->col_prec ) goto nomem1; + if ( row->col_prec == NULL ) { + goto nomem; + } + + row->col_type = (SQLSMALLINT *)ber_memcalloc_x( row->ncols, + sizeof( SQLSMALLINT ), ctx ); + if ( row->col_type == NULL ) { + goto nomem; + } + + row->cols = (char **)ber_memcalloc_x( row->ncols + 1, + sizeof( char * ), ctx ); + if ( row->cols == NULL ) { + goto nomem; + } + row->value_len = (SQLINTEGER *)ber_memcalloc_x( row->ncols, sizeof( SQLINTEGER ), ctx ); - if ( !row->value_len ) { + if ( row->value_len == NULL ) { + goto nomem; + } + + if ( 0 ) { +nomem: + ber_memfree_x( row->col_names, ctx ); + row->col_names = NULL; ber_memfree_x( row->col_prec, ctx ); row->col_prec = NULL; -nomem1: ber_memfree_x( row->cols, ctx ); + ber_memfree_x( row->col_type, ctx ); + row->col_type = NULL; + ber_memfree_x( row->cols, ctx ); row->cols = NULL; -nomem2: ber_memfree_x( row->col_names, ctx ); - row->col_names = NULL; -nomem3: Debug( LDAP_DEBUG_ANY, "backsql_BindRowAsStrings: " + ber_memfree_x( row->value_len, ctx ); + row->value_len = NULL; + + Debug( LDAP_DEBUG_ANY, "backsql_BindRowAsStrings: " "out of memory\n", 0, 0, 0 ); + return LDAP_NO_MEMORY; } - for ( i = 1; i <= row->ncols; i++ ) { - rc = SQLDescribeCol( sth, (SQLSMALLINT)i, &colname[ 0 ], + + for ( i = 0; i < row->ncols; i++ ) { + SQLSMALLINT TargetType; + + rc = SQLDescribeCol( sth, (SQLSMALLINT)(i + 1), &colname[ 0 ], (SQLUINTEGER)( sizeof( colname ) - 1 ), &name_len, &col_type, &col_prec, &col_scale, &col_null ); /* FIXME: test rc? */ ber_str2bv_x( (char *)colname, 0, 1, - &row->col_names[ i - 1 ], ctx ); + &row->col_names[ i ], ctx ); #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " "col_name=%s, col_prec[%d]=%d\n", - colname, (int)i, (int)col_prec ); + colname, (int)(i + 1), (int)col_prec ); #endif /* BACKSQL_TRACE */ if ( col_type != SQL_CHAR && col_type != SQL_VARCHAR ) { col_prec = MAX_ATTR_LEN; } - row->cols[ i - 1 ] = (char *)ber_memcalloc_x( col_prec + 1, + row->cols[ i ] = (char *)ber_memcalloc_x( col_prec + 1, sizeof( char ), ctx ); - row->col_prec[ i - 1 ] = col_prec; - rc = SQLBindCol( sth, (SQLUSMALLINT)i, - SQL_C_CHAR, - (SQLPOINTER)row->cols[ i - 1 ], - col_prec + 1, - &row->value_len[ i - 1 ] ); + row->col_prec[ i ] = col_prec; + row->col_type[ i ] = col_type; + + /* + * ITS#3386, ITS#3113 - 20070308 + * Note: there are many differences between various DPMS and ODBC + * Systems; some support SQL_C_BLOB, SQL_C_BLOB_LOCATOR. YMMV: + * This has only been tested on Linux/MySQL/UnixODBC + * For BINARY-type Fields (BLOB, etc), read the data as BINARY + */ + if ( BACKSQL_IS_BINARY( col_type ) ) { +#ifdef BACKSQL_TRACE + Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " + "col_name=%s, col_type[%d]=%d: reading binary data\n", + colname, (int)(i + 1), (int)col_type); +#endif /* BACKSQL_TRACE */ + TargetType = SQL_C_BINARY; + + } else { + /* Otherwise read it as Character data */ +#ifdef BACKSQL_TRACE + Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: " + "col_name=%s, col_type[%d]=%d: reading character data\n", + colname, (int)(i + 1), (int)col_type); +#endif /* BACKSQL_TRACE */ + TargetType = SQL_C_CHAR; + } + + rc = SQLBindCol( sth, (SQLUSMALLINT)(i + 1), + TargetType, + (SQLPOINTER)row->cols[ i ], + col_prec + 1, + &row->value_len[ i ] ); + /* FIXME: test rc? */ } - BER_BVZERO( &row->col_names[ i - 1 ] ); - row->cols[ i - 1 ] = NULL; + BER_BVZERO( &row->col_names[ i ] ); + row->cols[ i ] = NULL; } #ifdef BACKSQL_TRACE @@ -237,8 +290,9 @@ backsql_FreeRow_x( BACKSQL_ROW_NTS *row, void *ctx ) } ber_bvarray_free_x( row->col_names, ctx ); - ber_memvfree_x( (void **)row->cols, ctx ); ber_memfree_x( row->col_prec, ctx ); + ber_memfree_x( row->col_type, ctx ); + ber_memvfree_x( (void **)row->cols, ctx ); ber_memfree_x( row->value_len, ctx ); return SQL_SUCCESS; @@ -251,29 +305,15 @@ backsql_FreeRow( BACKSQL_ROW_NTS *row ) return backsql_FreeRow_x( row, NULL ); } -static int -backsql_cmp_connid( const void *v_c1, const void *v_c2 ) -{ - const backsql_db_conn *c1 = v_c1, *c2 = v_c2; - if ( c1->ldap_cid > c2->ldap_cid ) { - return 1; - } - - if ( c1->ldap_cid < c2->ldap_cid ) { - return -1; - } - - return 0; -} - static void -backsql_close_db_conn( void *v_conn ) +backsql_close_db_handle( SQLHDBC dbh ) { - backsql_db_conn *conn = (backsql_db_conn *)v_conn; - unsigned long cid = conn->ldap_cid; + if ( dbh == SQL_NULL_HDBC ) { + return; + } - Debug( LDAP_DEBUG_TRACE, "==>backsql_close_db_conn(%lu)\n", - cid, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "==>backsql_close_db_handle(%p)\n", + (void *)dbh, 0, 0 ); /* * Default transact is SQL_ROLLBACK; commit is required only @@ -282,21 +322,18 @@ backsql_close_db_conn( void *v_conn ) */ /* TimesTen */ - SQLTransact( SQL_NULL_HENV, conn->dbh, SQL_ROLLBACK ); - SQLDisconnect( conn->dbh ); - SQLFreeConnect( conn->dbh ); - ch_free( conn ); + SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); + SQLDisconnect( dbh ); + SQLFreeConnect( dbh ); - Debug( LDAP_DEBUG_TRACE, "<==backsql_close_db_conn(%lu)\n", - cid, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "<==backsql_close_db_handle(%p)\n", + (void *)dbh, 0, 0 ); } int backsql_conn_destroy( backsql_info *bi ) { - avl_free( bi->sql_db_conns, backsql_close_db_conn ); - return 0; } @@ -341,42 +378,44 @@ backsql_free_db_env( backsql_info *bi ) } static int -backsql_open_db_conn( backsql_info *bi, unsigned long ldap_cid, backsql_db_conn **pdbc ) +backsql_open_db_handle( + backsql_info *bi, + SQLHDBC *dbhp ) { /* TimesTen */ char DBMSName[ 32 ]; - backsql_db_conn *dbc; int rc; - assert( pdbc != NULL ); - *pdbc = NULL; + assert( dbhp != NULL ); + *dbhp = SQL_NULL_HDBC; - Debug( LDAP_DEBUG_TRACE, "==>backsql_open_db_conn(%lu)\n", - ldap_cid, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "==>backsql_open_db_handle()\n", + 0, 0, 0 ); - dbc = (backsql_db_conn *)ch_calloc( 1, sizeof( backsql_db_conn ) ); - dbc->ldap_cid = ldap_cid; - rc = SQLAllocConnect( bi->sql_db_env, &dbc->dbh ); + rc = SQLAllocConnect( bi->sql_db_env, dbhp ); if ( !BACKSQL_SUCCESS( rc ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " - "SQLAllocConnect() failed:\n", ldap_cid, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "backsql_open_db_handle(): " + "SQLAllocConnect() failed:\n", + 0, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, SQL_NULL_HDBC, - SQL_NULL_HENV, rc ); + SQL_NULL_HENV, rc ); return LDAP_UNAVAILABLE; } - rc = SQLConnect( dbc->dbh, - (SQLCHAR*)bi->sql_dbname, SQL_NTS, - (SQLCHAR*)bi->sql_dbuser, SQL_NTS, - (SQLCHAR*)bi->sql_dbpasswd, SQL_NTS ); + rc = SQLConnect( *dbhp, + (SQLCHAR*)bi->sql_dbname, SQL_NTS, + (SQLCHAR*)bi->sql_dbuser, SQL_NTS, + (SQLCHAR*)bi->sql_dbpasswd, SQL_NTS ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " + Debug( LDAP_DEBUG_TRACE, "backsql_open_db_handle(): " "SQLConnect() to database \"%s\" %s.\n", - ldap_cid, bi->sql_dbname, + bi->sql_dbname, rc == SQL_SUCCESS_WITH_INFO ? - "succeeded with info" : "failed" ); - backsql_PrintErrors( bi->sql_db_env, dbc->dbh, SQL_NULL_HENV, rc ); + "succeeded with info" : "failed", + 0 ); + backsql_PrintErrors( bi->sql_db_env, *dbhp, SQL_NULL_HENV, rc ); if ( rc != SQL_SUCCESS_WITH_INFO ) { + SQLFreeConnect( *dbhp ); return LDAP_UNAVAILABLE; } } @@ -385,7 +424,7 @@ backsql_open_db_conn( backsql_info *bi, unsigned long ldap_cid, backsql_db_conn * TimesTen : Turn off autocommit. We must explicitly * commit any transactions. */ - SQLSetConnectOption( dbc->dbh, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF ); + SQLSetConnectOption( *dbhp, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF ); /* * See if this connection is to TimesTen. If it is, @@ -394,112 +433,100 @@ backsql_open_db_conn( backsql_info *bi, unsigned long ldap_cid, backsql_db_conn /* Assume until proven otherwise */ bi->sql_flags &= ~BSQLF_USE_REVERSE_DN; DBMSName[ 0 ] = '\0'; - rc = SQLGetInfo( dbc->dbh, SQL_DBMS_NAME, (PTR)&DBMSName, + rc = SQLGetInfo( *dbhp, SQL_DBMS_NAME, (PTR)&DBMSName, sizeof( DBMSName ), NULL ); if ( rc == SQL_SUCCESS ) { if ( strcmp( DBMSName, "TimesTen" ) == 0 || - strcmp( DBMSName, "Front-Tier" ) == 0 ) { - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " - "TimesTen database!\n", ldap_cid, 0, 0 ); + strcmp( DBMSName, "Front-Tier" ) == 0 ) + { + Debug( LDAP_DEBUG_TRACE, "backsql_open_db_handle(): " + "TimesTen database!\n", + 0, 0, 0 ); bi->sql_flags |= BSQLF_USE_REVERSE_DN; } + } else { - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " - "SQLGetInfo() failed.\n", ldap_cid, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbc->dbh, SQL_NULL_HENV, rc ); - return rc; + Debug( LDAP_DEBUG_TRACE, "backsql_open_db_handle(): " + "SQLGetInfo() failed.\n", + 0, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, *dbhp, SQL_NULL_HENV, rc ); + SQLDisconnect( *dbhp ); + SQLFreeConnect( *dbhp ); + return LDAP_UNAVAILABLE; } /* end TimesTen */ - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " - "connected, adding to tree.\n", ldap_cid, 0, 0 ); - ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex ); - if ( avl_insert( &bi->sql_db_conns, dbc, backsql_cmp_connid, avl_dup_error ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): " - "duplicate connection ID.\n", ldap_cid, 0, 0 ); - return LDAP_OTHER; - } - ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex ); - Debug( LDAP_DEBUG_TRACE, "<==backsql_open_db_conn(%lu)\n", ldap_cid, 0, 0 ); - - *pdbc = dbc; + Debug( LDAP_DEBUG_TRACE, "<==backsql_open_db_handle()\n", + 0, 0, 0 ); return LDAP_SUCCESS; } int -backsql_free_db_conn( Operation *op ) +backsql_free_db_conn( Operation *op, SQLHDBC dbh ) { - backsql_info *bi = (backsql_info *)op->o_bd->be_private; - backsql_db_conn tmp = { 0 }, - *conn; - Debug( LDAP_DEBUG_TRACE, "==>backsql_free_db_conn()\n", 0, 0, 0 ); - tmp.ldap_cid = op->o_connid; - ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex ); - conn = avl_delete( &bi->sql_db_conns, &tmp, backsql_cmp_connid ); - ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex ); - /* - * we have one thread per connection, as I understand -- so we can - * get this out of critical section - */ - if ( conn != NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_free_db_conn(): " - "closing db connection %lu (%p)\n", - op->o_connid, (void *)conn, 0 ); - backsql_close_db_conn( (void *)conn ); - } + (void)backsql_close_db_handle( dbh ); Debug( LDAP_DEBUG_TRACE, "<==backsql_free_db_conn()\n", 0, 0, 0 ); - return conn ? SQL_SUCCESS : SQL_ERROR; + return LDAP_SUCCESS; +} + +static void *backsql_db_conn_dummy; + +static void +backsql_db_conn_keyfree( + void *key, + void *data ) +{ + backsql_close_db_handle( (SQLHDBC)data ); } int -backsql_get_db_conn( Operation *op, SQLHDBC *dbh ) +backsql_get_db_conn( Operation *op, SQLHDBC *dbhp ) { - backsql_info *bi = (backsql_info *)op->o_bd->be_private; - backsql_db_conn *dbc, - tmp = { 0 }; - int rc = LDAP_SUCCESS; + backsql_info *bi = (backsql_info *)op->o_bd->be_private; + int rc = LDAP_SUCCESS; + SQLHDBC dbh = SQL_NULL_HDBC; Debug( LDAP_DEBUG_TRACE, "==>backsql_get_db_conn()\n", 0, 0, 0 ); - assert( dbh != NULL ); - *dbh = SQL_NULL_HDBC; + assert( dbhp != NULL ); + *dbhp = SQL_NULL_HDBC; - tmp.ldap_cid = op->o_connid; + if ( op->o_threadctx ) { + void *data = NULL; - /* - * we have one thread per connection, as I understand -- - * so we do not need locking here - */ - dbc = avl_find( bi->sql_db_conns, &tmp, backsql_cmp_connid ); - if ( !dbc ) { - rc = backsql_open_db_conn( bi, op->o_connid, &dbc ); - if ( rc != LDAP_SUCCESS) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): " - "could not get connection handle " - "-- returning NULL\n", 0, 0, 0 ); - return rc; - } + ldap_pvt_thread_pool_getkey( op->o_threadctx, + &backsql_db_conn_dummy, &data, NULL ); + dbh = (SQLHDBC)data; + + } else { + dbh = bi->sql_dbh; } - ldap_pvt_thread_mutex_lock( &bi->sql_schema_mutex ); - if ( !BACKSQL_SCHEMA_LOADED( bi ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): " - "first call -- reading schema map\n", 0, 0, 0 ); - rc = backsql_load_schema_map( bi, dbc->dbh ); + if ( dbh == SQL_NULL_HDBC ) { + rc = backsql_open_db_handle( bi, &dbh ); if ( rc != LDAP_SUCCESS ) { - ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex ); - backsql_free_db_conn( op ); return rc; } + + if ( op->o_threadctx ) { + void *data = NULL; + + data = (void *)dbh; + ldap_pvt_thread_pool_setkey( op->o_threadctx, + &backsql_db_conn_dummy, data, + backsql_db_conn_keyfree ); + + } else { + bi->sql_dbh = dbh; + } } - ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex ); - *dbh = dbc->dbh; + *dbhp = dbh; Debug( LDAP_DEBUG_TRACE, "<==backsql_get_db_conn()\n", 0, 0, 0 ); diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 8bb21b5591..3d83060f55 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -34,6 +34,7 @@ #include #include "slap.h" +#include "config.h" #include "lutil.h" #include "lber_pvt.h" @@ -189,7 +190,7 @@ backend_set_controls( BackendDB *be ) } /* startup a specific backend database */ -int backend_startup_one(Backend *be) +int backend_startup_one(Backend *be, ConfigReply *cr) { int rc = 0; @@ -208,8 +209,19 @@ int backend_startup_one(Backend *be) /* set database controls */ (void)backend_set_controls( be ); +#if 0 + if ( !BER_BVISEMPTY( &be->be_rootndn ) + && select_backend( &be->be_rootndn, 0 ) == be + && BER_BVISNULL( &be->be_rootpw ) ) + { + /* warning: if rootdn entry is created, + * it can take rootdn privileges; + * set empty rootpw to prevent */ + } +#endif + if ( be->bd_info->bi_db_open ) { - rc = be->bd_info->bi_db_open( be ); + rc = be->bd_info->bi_db_open( be, cr ); if ( rc == 0 ) { (void)backend_set_controls( be ); @@ -228,6 +240,7 @@ int backend_startup(Backend *be) int i; int rc = 0; BackendInfo *bi; + ConfigReply cr={0, ""}; if( ! ( nBackendDB > 0 ) ) { /* no databases */ @@ -251,12 +264,12 @@ int backend_startup(Backend *be) /* append global access controls */ acl_append( &be->be_acl, frontendDB->be_acl, -1 ); - return backend_startup_one( be ); + return backend_startup_one( be, &cr ); } /* open frontend, if required */ if ( frontendDB->bd_info->bi_db_open ) { - rc = frontendDB->bd_info->bi_db_open( frontendDB ); + rc = frontendDB->bd_info->bi_db_open( frontendDB, NULL ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "backend_startup: bi_db_open(frontend) failed! (%d)\n", @@ -300,7 +313,7 @@ int backend_startup(Backend *be) /* append global access controls */ acl_append( &be->be_acl, frontendDB->be_acl, -1 ); - rc = backend_startup_one( be ); + rc = backend_startup_one( be, &cr ); if ( rc ) return rc; } @@ -336,7 +349,7 @@ int backend_shutdown( Backend *be ) } if ( be->bd_info->bi_db_close ) { - be->bd_info->bi_db_close( be ); + be->bd_info->bi_db_close( be, NULL ); } if( be->bd_info->bi_close ) { @@ -349,7 +362,7 @@ int backend_shutdown( Backend *be ) /* close each backend database */ LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { if ( be->bd_info->bi_db_close ) { - be->bd_info->bi_db_close( be ); + be->bd_info->bi_db_close( be, NULL ); } if(rc != 0) { @@ -373,7 +386,7 @@ int backend_shutdown( Backend *be ) /* close frontend, if required */ if ( frontendDB->bd_info->bi_db_close ) { - rc = frontendDB->bd_info->bi_db_close ( frontendDB ); + rc = frontendDB->bd_info->bi_db_close ( frontendDB, NULL ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "backend_startup: bi_db_close(frontend) failed! (%d)\n", @@ -411,14 +424,14 @@ backend_stopdown_one( BackendDB *bd ) } if ( bd->bd_info->bi_db_destroy ) { - bd->bd_info->bi_db_destroy( bd ); + bd->bd_info->bi_db_destroy( bd, NULL ); } } void backend_destroy_one( BackendDB *bd, int dynamic ) { if ( dynamic ) { - LDAP_STAILQ_REMOVE(&backendDB, bd, slap_backend_db, be_next ); + LDAP_STAILQ_REMOVE(&backendDB, bd, BackendDB, be_next ); } if ( bd->be_syncinfo ) { @@ -440,16 +453,6 @@ void backend_destroy_one( BackendDB *bd, int dynamic ) } acl_destroy( bd->be_acl, frontendDB->be_acl ); limits_destroy( bd->be_limits ); - if ( bd->be_replogfile ) { - ch_free( bd->be_replogfile ); - } - if ( bd->be_replica_argsfile ) { - ch_free( bd->be_replica_argsfile ); - } - if ( bd->be_replica_pidfile ) { - ch_free( bd->be_replica_pidfile ); - } - destroy_replica_info( bd ); if ( !BER_BVISNULL( &bd->be_update_ndn ) ) { ch_free( bd->be_update_ndn.bv_val ); } @@ -486,7 +489,7 @@ int backend_destroy(void) bd = frontendDB; if ( bd ) { if ( bd->bd_info->bi_db_destroy ) { - bd->bd_info->bi_db_destroy( bd ); + bd->bd_info->bi_db_destroy( bd, NULL ); } ber_bvarray_free( bd->be_suffix ); ber_bvarray_free( bd->be_nsuffix ); @@ -500,17 +503,6 @@ int backend_destroy(void) free( bd->be_rootpw.bv_val ); } acl_destroy( bd->be_acl, frontendDB->be_acl ); - - if ( bd->be_replogfile != NULL ) { - free( bd->be_replogfile ); - } - if ( bd->be_replica_argsfile ) { - ch_free( bd->be_replica_argsfile ); - } - if ( bd->be_replica_pidfile ) { - ch_free( bd->be_replica_pidfile ); - } - assert( bd->be_replica == NULL ); } return 0; @@ -560,7 +552,7 @@ backend_db_move( int idx ) { - LDAP_STAILQ_REMOVE(&backendDB, be, slap_backend_db, be_next); + LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next); backend_db_insert(be, idx); } @@ -568,7 +560,8 @@ BackendDB * backend_db_init( const char *type, BackendDB *b0, - int idx ) + int idx, + ConfigReply *cr) { BackendInfo *bi = backend_info(type); BackendDB *be = b0; @@ -607,14 +600,14 @@ backend_db_init( be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; if ( bi->bi_db_init ) { - rc = bi->bi_db_init( be ); + rc = bi->bi_db_init( be, cr ); } if ( rc != 0 ) { fprintf( stderr, "database init failed (%s)\n", type ); /* If we created and linked this be, remove it and free it */ if ( !b0 ) { - LDAP_STAILQ_REMOVE(&backendDB, be, slap_backend_db, be_next); + LDAP_STAILQ_REMOVE(&backendDB, be, BackendDB, be_next); ch_free( be ); be = NULL; nbackends--; @@ -632,12 +625,12 @@ be_db_close( void ) LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { if ( be->bd_info->bi_db_close ) { - be->bd_info->bi_db_close( be ); + be->bd_info->bi_db_close( be, NULL ); } } if ( frontendDB->bd_info->bi_db_close ) { - frontendDB->bd_info->bi_db_close( frontendDB ); + frontendDB->bd_info->bi_db_close( frontendDB, NULL ); } } @@ -645,12 +638,11 @@ be_db_close( void ) Backend * select_backend( struct berval * dn, - int manageDSAit, int noSubs ) { int j; ber_len_t len, dnlen = dn->bv_len; - Backend *be, *b2 = NULL; + Backend *be; LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { if ( be->be_nsuffix == NULL || SLAP_DBHIDDEN( be )) { @@ -684,28 +676,12 @@ select_backend( if ( strcmp( be->be_nsuffix[j].bv_val, &dn->bv_val[dnlen-len] ) == 0 ) { - if( b2 == NULL ) { - b2 = be; - - if( manageDSAit && len == dnlen && - !SLAP_GLUE_SUBORDINATE( be ) ) { - continue; - } - } else { - /* If any parts of the tree are glued, use the first - * match regardless of manageDSAit. Otherwise use the - * last match. - */ - if( !( SLAP_DBFLAGS( be ) & ( SLAP_DBFLAG_GLUE_INSTANCE | - SLAP_DBFLAG_GLUE_SUBORDINATE ))) - b2 = be; - } - return b2; + return be; } } } - return b2; + return be; } int @@ -728,6 +704,26 @@ be_issuffix( return 0; } +int +be_issubordinate( + Backend *be, + struct berval *bvsubordinate ) +{ + int i; + + if ( be->be_nsuffix == NULL ) { + return 0; + } + + for ( i = 0; !BER_BVISNULL( &be->be_nsuffix[i] ); i++ ) { + if ( dnIsSuffix( bvsubordinate, &be->be_nsuffix[i] ) ) { + return 1; + } + } + + return 0; +} + int be_isroot_dn( Backend *be, struct berval *ndn ) { @@ -780,14 +776,46 @@ be_isroot( Operation *op ) int be_isroot_pw( Operation *op ) { - int result; + return be_rootdn_bind( op, NULL ) == LDAP_SUCCESS; +} - if ( ! be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { - return 0; +/* + * checks if binding as rootdn + * + * return value: + * SLAP_CB_CONTINUE if not the rootdn + * LDAP_SUCCESS if rootdn & rootpw + * LDAP_INVALID_CREDENTIALS if rootdn & !rootpw + * + * if rs != NULL + * if LDAP_SUCCESS, op->orb_edn is set + * if LDAP_INVALID_CREDENTIALS, response is sent to client + */ +int +be_rootdn_bind( Operation *op, SlapReply *rs ) +{ + int rc; + + assert( op->o_tag == LDAP_REQ_BIND ); + assert( op->orb_method == LDAP_AUTH_SIMPLE ); + + if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { + return SLAP_CB_CONTINUE; + } + + if ( BER_BVISNULL( &op->o_bd->be_rootpw ) ) { + /* give the database a chance */ + return SLAP_CB_CONTINUE; } if ( BER_BVISEMPTY( &op->o_bd->be_rootpw ) ) { - return 0; + /* rootdn bind explicitly disallowed */ + rc = LDAP_INVALID_CREDENTIALS; + if ( rs ) { + goto send_result; + } + + return rc; } #ifdef SLAPD_SPASSWD @@ -795,13 +823,31 @@ be_isroot_pw( Operation *op ) op->o_conn->c_sasl_authctx, NULL ); #endif - result = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL ); + rc = lutil_passwd( &op->o_bd->be_rootpw, &op->orb_cred, NULL, NULL ); #ifdef SLAPD_SPASSWD ldap_pvt_thread_pool_setkey( op->o_threadctx, slap_sasl_bind, NULL, NULL ); #endif - return result == 0; + rc = ( rc == 0 ? LDAP_SUCCESS : LDAP_INVALID_CREDENTIALS ); + if ( rs ) { +send_result:; + rs->sr_err = rc; + + Debug( LDAP_DEBUG_TRACE, "%s: rootdn=\"%s\" bind%s\n", + op->o_log_prefix, op->o_bd->be_rootdn.bv_val, + rc == LDAP_SUCCESS ? " succeeded" : " failed" ); + + if ( rc == LDAP_SUCCESS ) { + /* Set to the pretty rootdn */ + ber_dupbv( &op->orb_edn, &op->o_bd->be_rootdn ); + + } else { + send_ldap_result( op, rs ); + } + } + + return rc; } int @@ -1300,7 +1346,7 @@ fe_acl_group( GroupAssertion *g; Backend *be = op->o_bd; - op->o_bd = select_backend( gr_ndn, 0, 0 ); + op->o_bd = select_backend( gr_ndn, 0 ); for ( g = op->o_groups; g; g = g->ga_next ) { if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || @@ -1321,124 +1367,159 @@ fe_acl_group( if ( target && dn_match( &target->e_nname, gr_ndn ) ) { e = target; rc = 0; + } else { op->o_private = NULL; rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); e_priv = op->o_private; op->o_private = o_priv; } + if ( e ) { a = attr_find( e->e_attrs, group_at ); if ( a ) { - /* If the attribute is a subtype of labeledURI, treat this as - * a dynamic group ala groupOfURLs + /* If the attribute is a subtype of labeledURI, + * treat this as a dynamic group ala groupOfURLs */ - if (is_at_subtype( group_at->ad_type, + if ( is_at_subtype( group_at->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { int i; LDAPURLDesc *ludp; struct berval bv, nbase; Filter *filter; - Entry *user; + Entry *user = NULL; void *user_priv = NULL; Backend *b2 = op->o_bd; if ( target && dn_match( &target->e_nname, op_ndn ) ) { user = target; - } else { - op->o_bd = select_backend( op_ndn, 0, 0 ); - op->o_private = NULL; - rc = be_entry_get_rw(op, op_ndn, NULL, NULL, 0, &user ); - user_priv = op->o_private; - op->o_private = o_priv; } - if ( rc == 0 ) { - rc = LDAP_COMPARE_FALSE; - for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { - if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != - LDAP_URL_SUCCESS ) - { - continue; + rc = LDAP_COMPARE_FALSE; + for ( i = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) { + if ( ldap_url_parse( a->a_vals[i].bv_val, &ludp ) != + LDAP_URL_SUCCESS ) + { + continue; + } + + BER_BVZERO( &nbase ); + + /* host, attrs and extensions parts must be empty */ + if ( ( ludp->lud_host && *ludp->lud_host ) + || ludp->lud_attrs + || ludp->lud_exts ) + { + goto loopit; + } + + ber_str2bv( ludp->lud_dn, 0, 0, &bv ); + if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, + op->o_tmpmemctx ) != LDAP_SUCCESS ) + { + goto loopit; + } + + switch ( ludp->lud_scope ) { + case LDAP_SCOPE_BASE: + if ( !dn_match( &nbase, op_ndn ) ) { + goto loopit; } - BER_BVZERO( &nbase ); - /* host part must be empty */ - /* attrs and extensions parts must be empty */ - if ( ( ludp->lud_host && *ludp->lud_host ) || - ludp->lud_attrs || ludp->lud_exts ) - { + break; + case LDAP_SCOPE_ONELEVEL: + dnParent( op_ndn, &bv ); + if ( !dn_match( &nbase, &bv ) ) { goto loopit; } - ber_str2bv( ludp->lud_dn, 0, 0, &bv ); - if ( dnNormalize( 0, NULL, NULL, &bv, &nbase, - op->o_tmpmemctx ) != LDAP_SUCCESS ) + break; + case LDAP_SCOPE_SUBTREE: + if ( !dnIsSuffix( op_ndn, &nbase ) ) { + goto loopit; + } + break; + case LDAP_SCOPE_SUBORDINATE: + if ( dn_match( &nbase, op_ndn ) || + !dnIsSuffix( op_ndn, &nbase ) ) { goto loopit; } - switch ( ludp->lud_scope ) { - case LDAP_SCOPE_BASE: - if ( !dn_match( &nbase, op_ndn ) ) { - goto loopit; - } - break; - case LDAP_SCOPE_ONELEVEL: - dnParent( op_ndn, &bv ); - if ( !dn_match( &nbase, &bv ) ) { - goto loopit; - } - break; - case LDAP_SCOPE_SUBTREE: - if ( !dnIsSuffix( op_ndn, &nbase ) ) { - goto loopit; - } - break; - case LDAP_SCOPE_SUBORDINATE: - if ( dn_match( &nbase, op_ndn ) || - !dnIsSuffix( op_ndn, &nbase ) ) - { + } + + /* NOTE: this could be NULL + * if no filter is provided, + * or if filter parsing fails. + * In the latter case, + * we should give up. */ + if ( ludp->lud_filter != NULL && ludp->lud_filter != '\0') { + filter = str2filter_x( op, ludp->lud_filter ); + if ( filter == NULL ) { + /* give up... */ + rc = LDAP_OTHER; + goto loopit; + } + + /* only get user if required + * and not available yet */ + if ( user == NULL ) { + int rc2; + + op->o_bd = select_backend( op_ndn, 0 ); + op->o_private = NULL; + rc2 = be_entry_get_rw( op, op_ndn, NULL, NULL, 0, &user ); + user_priv = op->o_private; + op->o_private = o_priv; + if ( rc2 != 0 ) { + /* give up... */ + rc = LDAP_OTHER; goto loopit; } } - filter = str2filter_x( op, ludp->lud_filter ); - if ( filter ) { - if ( test_filter( NULL, user, filter ) == - LDAP_COMPARE_TRUE ) - { - rc = 0; - } - filter_free_x( op, filter ); + + if ( test_filter( NULL, user, filter ) == + LDAP_COMPARE_TRUE ) + { + rc = 0; } + filter_free_x( op, filter ); + } loopit: - ldap_free_urldesc( ludp ); - if ( !BER_BVISNULL( &nbase ) ) { - op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx ); - } - if ( rc == 0 ) break; + ldap_free_urldesc( ludp ); + if ( !BER_BVISNULL( &nbase ) ) { + op->o_tmpfree( nbase.bv_val, op->o_tmpmemctx ); } - if ( user != target ) { - op->o_private = user_priv; - be_entry_release_r( op, user ); - op->o_private = o_priv; + if ( rc != LDAP_COMPARE_FALSE ) { + break; } } + + if ( user != NULL && user != target ) { + op->o_private = user_priv; + be_entry_release_r( op, user ); + op->o_private = o_priv; + } op->o_bd = b2; + } else { rc = value_find_ex( group_at, - SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | - SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, op_ndn, op->o_tmpmemctx ); - if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, op_ndn, op->o_tmpmemctx ); + if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) { rc = LDAP_COMPARE_FALSE; + } } + } else { rc = LDAP_NO_SUCH_ATTRIBUTE; } + if ( e != target ) { op->o_private = e_priv; be_entry_release_r( op, e ); op->o_private = o_priv; } + } else { rc = LDAP_NO_SUCH_OBJECT; } @@ -1455,6 +1536,7 @@ loopit: g->ga_next = op->o_groups; op->o_groups = g; } + done: op->o_bd = be; return rc; @@ -1501,7 +1583,7 @@ fe_acl_attribute( AccessControlState acl_state = ACL_STATE_INIT; Backend *be = op->o_bd; - op->o_bd = select_backend( edn, 0, 0 ); + op->o_bd = select_backend( edn, 0 ); if ( target && dn_match( &target->e_nname, edn ) ) { e = target; @@ -1654,7 +1736,7 @@ backend_access( assert( edn != NULL ); assert( access > ACL_NONE ); - op->o_bd = select_backend( edn, 0, 0 ); + op->o_bd = select_backend( edn, 0 ); if ( target && dn_match( &target->e_nname, edn ) ) { e = target; @@ -1776,7 +1858,7 @@ fe_aux_operational( BackendDB *be_orig = op->o_bd; /* Let the overlays have a chance at this */ - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd != NULL && !be_match( op->o_bd, frontendDB ) && ( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) && op->o_bd->be_operational != NULL ) diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c index 58cdab69b6..78d0633cc2 100644 --- a/servers/slapd/backglue.c +++ b/servers/slapd/backglue.c @@ -35,6 +35,7 @@ #define SLAPD_TOOLS #include "slap.h" +#include "config.h" typedef struct gluenode { BackendDB *gn_be; @@ -583,7 +584,7 @@ glue_open ( gi->gi_n[i].gn_be->bd_info ); /* Let backend.c take care of the rest of startup */ if ( !rc ) - rc = backend_startup_one( gi->gi_n[i].gn_be ); + rc = backend_startup_one( gi->gi_n[i].gn_be, NULL ); if ( rc ) break; } if ( !rc && !bsame && on->on_info->oi_orig->bi_open ) @@ -816,7 +817,8 @@ glue_tool_sync ( static int glue_db_init( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -861,7 +863,6 @@ glue_db_init( /*FIXME : need to add support */ oi->oi_bi.bi_tool_dn2id_get = 0; - oi->oi_bi.bi_tool_id2entry_get = 0; oi->oi_bi.bi_tool_entry_modify = 0; SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE; @@ -871,7 +872,8 @@ glue_db_init( static int glue_db_destroy ( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -883,7 +885,8 @@ glue_db_destroy ( static int glue_db_close( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; diff --git a/servers/slapd/backover.c b/servers/slapd/backover.c index eccc395fed..874ccf065a 100644 --- a/servers/slapd/backover.c +++ b/servers/slapd/backover.c @@ -51,14 +51,14 @@ over_db_func( func = &oi->oi_orig->bi_db_open; if ( func[which] ) { be->bd_info = oi->oi_orig; - rc = func[which]( be ); + rc = func[which]( be, NULL ); } for (; on && rc == 0; on=on->on_next) { be->bd_info = &on->on_bi; func = &on->on_bi.bi_db_open; if (func[which]) { - rc = func[which]( be ); + rc = func[which]( be, NULL ); } } be->bd_info = bi_orig; @@ -147,6 +147,7 @@ over_db_config( ca.bi = &on->on_bi; ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca ); if ( ct ) { + ca.table = on->on_bi.bi_cf_ocs->co_type; rc = config_add_vals( ct, &ca ); if ( rc != SLAP_CONF_UNKNOWN ) break; @@ -167,7 +168,8 @@ over_db_config( static int over_db_open( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { return over_db_func( be, db_open ); @@ -175,7 +177,8 @@ over_db_open( static int over_db_close( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinfo *oi = be->bd_info->bi_private; @@ -186,13 +189,13 @@ over_db_close( for (; on && rc == 0; on=on->on_next) { be->bd_info = &on->on_bi; if ( be->bd_info->bi_db_close ) { - rc = be->bd_info->bi_db_close( be ); + rc = be->bd_info->bi_db_close( be, NULL ); } } if ( oi->oi_orig->bi_db_close ) { be->bd_info = oi->oi_orig; - rc = be->bd_info->bi_db_close( be ); + rc = be->bd_info->bi_db_close( be, NULL ); } be->bd_info = bi_orig; @@ -201,7 +204,8 @@ over_db_close( static int over_db_destroy( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinfo *oi = be->bd_info->bi_private; @@ -1074,7 +1078,7 @@ overlay_destroy_one( BackendDB *be, slap_overinst *on ) if ( on->on_bi.bi_db_destroy ) { BackendInfo *bi_orig = be->bd_info; be->bd_info = (BackendInfo *)on; - on->on_bi.bi_db_destroy( be ); + on->on_bi.bi_db_destroy( be, NULL ); be->bd_info = bi_orig; } free( on ); @@ -1280,7 +1284,7 @@ overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res ) if ( on2->on_bi.bi_db_init ) { int rc; be->bd_info = (BackendInfo *)on2; - rc = on2->on_bi.bi_db_init( be ); + rc = on2->on_bi.bi_db_init( be, NULL ); be->bd_info = (BackendInfo *)oi; if ( rc ) { *prev = on2->on_next; diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index baa42e446c..19e7b569b3 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -125,10 +125,10 @@ static ConfigDriver config_requires; static ConfigDriver config_security; static ConfigDriver config_referral; static ConfigDriver config_loglevel; -static ConfigDriver config_replica; static ConfigDriver config_updatedn; static ConfigDriver config_updateref; static ConfigDriver config_include; +static ConfigDriver config_obsolete; #ifdef HAVE_TLS static ConfigDriver config_tls_option; static ConfigDriver config_tls_config; @@ -148,6 +148,7 @@ enum { CFG_TLS_DH_FILE, CFG_TLS_VERIFY, CFG_TLS_CRLCHECK, + CFG_TLS_CRL_FILE, CFG_CONCUR, CFG_THREADS, CFG_SALT, @@ -160,10 +161,6 @@ enum { CFG_DIT, CFG_ATTR, CFG_ATOPT, - CFG_REPLICA_ARGSFILE, - CFG_REPLICA_PIDFILE, - CFG_REPLICATIONINTERVAL, - CFG_REPLOG, CFG_ROOTDSE, CFG_LOGFILE, CFG_PLUGIN, @@ -224,6 +221,9 @@ static OidRec OidMacros[] = { * OLcfg{Bk|Db}{Oc|At}:1 -> back-bdb(/back-hdb) * OLcfg{Bk|Db}{Oc|At}:2 -> back-ldif * OLcfg{Bk|Db}{Oc|At}:3 -> back-ldap + * OLcfg{Bk|Db}{Oc|At}:4 -> back-monitor + * OLcfg{Bk|Db}{Oc|At}:5 -> back-relay + * OLcfg{Bk|Db}{Oc|At}:6 -> back-sql */ /* @@ -239,12 +239,16 @@ static OidRec OidMacros[] = { * OLcfgOv{Oc|At}:7 -> distproc * OLcfgOv{Oc|At}:8 -> dynlist * OLcfgOv{Oc|At}:9 -> dds - * OLcfgOv{Oc|At}:10 -> unique - * OLcfgOv{Oc|At}:11 -> refint - * OLcfgOv{Oc|At}:12 -> ppolicy - * OLcfgOv{Oc|At}:13 -> constraint - * OLcfgOv{Oc|At}:14 -> translucent - * OLcfgOv{Oc|At}:15 -> auditlog + * OLcfgOv{Oc|At}:10 -> unique + * OLcfgOv{Oc|At}:11 -> refint + * OLcfgOv{Oc|At}:12 -> ppolicy + * OLcfgOv{Oc|At}:13 -> constraint + * OLcfgOv{Oc|At}:14 -> translucent + * OLcfgOv{Oc|At}:15 -> auditlog + * OLcfgOv{Oc|At}:16 -> rwm + * OLcfgOv{Oc|At}:17 -> dyngroup + * OLcfgOv{Oc|At}:18 -> memberof + * OLcfgOv{Oc|At}:19 -> collect */ /* alphabetical ordering */ @@ -389,7 +393,7 @@ static ConfigTable config_back_cf_table[] = { "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "moduleload", "file", 2, 0, 0, #ifdef SLAPD_MODULES - ARG_MAGIC|CFG_MODLOAD, &config_generic, + ARG_MAGIC|CFG_MODLOAD|ARG_NO_DELETE, &config_generic, #else ARG_IGNORED, NULL, #endif @@ -455,20 +459,20 @@ static ConfigTable config_back_cf_table[] = { &config_referral, "( OLcfgGlAt:41 NAME 'olcReferral' " "SUP labeledURI SINGLE-VALUE )", NULL, NULL }, { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC, - &config_replica, "( OLcfgDbAt:0.7 NAME 'olcReplica' " + &config_obsolete, "( OLcfgDbAt:0.7 NAME 'olcReplica' " "EQUALITY caseIgnoreMatch " "SUP labeledURI X-ORDERED 'VALUES' )", NULL, NULL }, - { "replica-argsfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|ARG_STRING|CFG_REPLICA_ARGSFILE, - &config_generic, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' " + { "replica-argsfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC, + &config_obsolete, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "replica-pidfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|ARG_STRING|CFG_REPLICA_PIDFILE, - &config_generic, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' " + { "replica-pidfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC, + &config_obsolete, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "replicationInterval", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|ARG_INT|CFG_REPLICATIONINTERVAL, - &config_generic, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' " + { "replicationInterval", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC, + &config_obsolete, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, - { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC|ARG_STRING|CFG_REPLOG, - &config_generic, "( OLcfgGlAt:46 NAME 'olcReplogFile' " + { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC, + &config_obsolete, "( OLcfgGlAt:46 NAME 'olcReplogFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC, &config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' " @@ -616,6 +620,14 @@ static ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "TLSCRLFile", NULL, 0, 0, 0, +#if defined(HAVE_GNUTLS) + CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option, +#else + ARG_IGNORED, NULL, +#endif + "( OLcfgGlAt:82 NAME 'olcTLSCRLFile' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSRandFile", NULL, 0, 0, 0, #ifdef HAVE_TLS CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option, @@ -689,7 +701,7 @@ static ConfigOCs cf_ocs[] = { "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ " "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ " "olcLogLevel $ " - "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ " + "olcPasswordCryptSaltFormat $ olcPidFile $ " "olcPluginLogFile $ olcReadOnly $ olcReferral $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ " "olcRootDSE $ " @@ -700,7 +712,7 @@ static ConfigOCs cf_ocs[] = { "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ " - "olcToolThreads $ " + "olcTLSCRLFile $ olcToolThreads $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " "olcDitContentRules ) )", Cft_Global }, { "( OLcfgGlOc:2 " @@ -742,7 +754,7 @@ static ConfigOCs cf_ocs[] = { "NAME 'olcFrontendConfig' " "DESC 'OpenLDAP frontend configuration' " "AUXILIARY " - "MAY olcDefaultSearchBase )", + "MAY ( olcDefaultSearchBase $ olcPasswordHash ) )", Cft_Database, NULL, NULL }, #ifdef SLAPD_MODULES { "( OLcfgGlOc:8 " @@ -789,7 +801,6 @@ config_generic(ConfigArgs *c) { if ( c->be->be_limits ) { char buf[4096*3]; struct berval bv; - int i; for ( i=0; c->be->be_limits[i]; i++ ) { bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i ); @@ -921,25 +932,6 @@ config_generic(ConfigArgs *c) { rc = (!i); break; } - case CFG_REPLICA_ARGSFILE: - if ( c->be->be_replica_argsfile ) - c->value_string = ch_strdup( c->be->be_replica_argsfile ); - break; - case CFG_REPLICA_PIDFILE: - if ( c->be->be_replica_pidfile ) - c->value_string = ch_strdup( c->be->be_replica_pidfile ); - break; - case CFG_REPLICATIONINTERVAL: - if ( c->be->be_replicationinterval > 0 ) { - c->value_int = c->be->be_replicationinterval; - } else { - rc = 1; - } - break; - case CFG_REPLOG: - if ( c->be->be_replogfile ) - c->value_string = ch_strdup( c->be->be_replogfile ); - break; case CFG_ROOTDSE: { ConfigFile *cf = c->private; if ( cf->c_dseFiles ) { @@ -953,9 +945,9 @@ config_generic(ConfigArgs *c) { if ( sid_list ) { ServerID *si; struct berval bv; - char *ptr; for ( si = sid_list; si; si=si->si_next ) { + assert( si->si_num >= 0 && si->si_num <= SLAP_SYNC_SID_MAX ); if ( !BER_BVISEMPTY( &si->si_url )) { bv.bv_len = si->si_url.bv_len + 6; bv.bv_val = ch_malloc( bv.bv_len ); @@ -1097,32 +1089,12 @@ config_generic(ConfigArgs *c) { passwd_salt = NULL; break; - case CFG_REPLICA_ARGSFILE: - ch_free( c->be->be_replica_argsfile ); - c->be->be_replica_argsfile = NULL; - break; - - case CFG_REPLICA_PIDFILE: - ch_free( c->be->be_replica_pidfile ); - c->be->be_replica_pidfile = NULL; - break; - - case CFG_REPLICATIONINTERVAL: - c->be->be_replicationinterval = 0; - break; - - case CFG_REPLOG: - ch_free( c->be->be_replogfile ); - c->be->be_replogfile = NULL; - break; - case CFG_LOGFILE: ch_free( logfileName ); logfileName = NULL; break; case CFG_SERVERID: { - int i; ServerID *si, **sip; for ( i=0, si = sid_list, sip = &sid_list; @@ -1184,7 +1156,6 @@ config_generic(ConfigArgs *c) { cfn->c_oc_head = cfn->c_oc_tail = NULL; } else { ObjectClass *oc, *prev = NULL; - int i; for ( i=0, oc=cfn->c_oc_head; ivalx; i++) { prev = oc; @@ -1219,7 +1190,6 @@ config_generic(ConfigArgs *c) { cfn->c_at_head = cfn->c_at_tail = NULL; } else { AttributeType *at, *prev = NULL; - int i; for ( i=0, at=cfn->c_at_head; ivalx; i++) { prev = at; @@ -1256,9 +1226,9 @@ config_generic(ConfigArgs *c) { switch(c->type) { case CFG_BACKEND: if(!(c->bi = backend_info(c->argv[1]))) { - snprintf( c->msg, sizeof( c->msg ), "<%s> failed init", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return(1); } break; @@ -1272,11 +1242,11 @@ config_generic(ConfigArgs *c) { } else if ( !strcasecmp( c->argv[1], "frontend" )) { c->be = frontendDB; } else { - c->be = backend_db_init(c->argv[1], NULL, c->valx); + c->be = backend_db_init(c->argv[1], NULL, c->valx, &c->reply); if ( !c->be ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> failed init", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", - c->log, c->msg, c->argv[1] ); + if ( c->cr_msg[0] == 0 ) + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", c->log, c->cr_msg, c->argv[1] ); return(1); } } @@ -1288,19 +1258,19 @@ config_generic(ConfigArgs *c) { case CFG_THREADS: if ( c->value_int < 2 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "threads=%d smaller than minimum value 2", c->value_int ); Debug(LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "warning, threads=%d larger than twice the default (2*%d=%d); YMMV", c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS ); Debug(LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); } if ( slapMode & SLAP_SERVER_MODE ) ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int); @@ -1334,9 +1304,9 @@ config_generic(ConfigArgs *c) { case CFG_AZPOLICY: ch_free(c->value_string); if (slap_sasl_setpolicy( c->argv[1] )) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse value", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return(1); } break; @@ -1351,9 +1321,9 @@ config_generic(ConfigArgs *c) { { char *txt = slap_sasl_secprops( c->argv[1] ); if ( txt ) { - snprintf( c->msg, sizeof(c->msg), "<%s> %s", + snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> %s", c->argv[0], txt ); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 ); return(1); } break; @@ -1473,90 +1443,11 @@ config_generic(ConfigArgs *c) { } break; - case CFG_REPLICA_ARGSFILE: - if(SLAP_MONITOR(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replica-argsfile\" should not be used " - "inside monitor database\n", - c->log, 0, 0); - /* FIXME: should this be an error? */ - return(0); - } - - if ( c->be->be_replica_argsfile != NULL ) { - /* FIXME: error? */ - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replica-argsfile\" already provided; " - "replacing \"%s\" with \"%s\".\n", - c->log, c->be->be_replica_argsfile, c->value_string ); - ch_free( c->be->be_replica_argsfile ); - } - - c->be->be_replica_argsfile = c->value_string; - break; - - case CFG_REPLICA_PIDFILE: - if(SLAP_MONITOR(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replica-pidfile\" should not be used " - "inside monitor database\n", - c->log, 0, 0); - /* FIXME: should this be an error? */ - return(0); - } - - if ( c->be->be_replica_pidfile != NULL ) { - /* FIXME: error? */ - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replica-pidfile\" already provided; " - "replacing \"%s\" with \"%s\".\n", - c->log, c->be->be_replica_pidfile, c->value_string ); - ch_free( c->be->be_replica_pidfile ); - } - - c->be->be_replica_pidfile = c->value_string; - break; - - case CFG_REPLICATIONINTERVAL: - if(SLAP_MONITOR(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replicationinterval\" should not be used " - "inside monitor database\n", - c->log, 0, 0); - /* FIXME: should this be an error? */ - return(0); - } - - c->be->be_replicationinterval = c->value_int; - break; - - case CFG_REPLOG: - if(SLAP_MONITOR(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replogfile\" should not be used " - "inside monitor database\n", - c->log, 0, 0); - /* FIXME: should this be an error? */ - return(0); - } - - if ( c->be->be_replogfile != NULL ) { - /* FIXME: error? */ - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replogfile\" already provided; " - "replacing \"%s\" with \"%s\".\n", - c->log, c->be->be_replogfile, c->value_string ); - ch_free( c->be->be_replogfile ); - } - - c->be->be_replogfile = c->value_string; - break; - case CFG_ROOTDSE: if(root_dse_read_file(c->argv[1])) { - snprintf( c->msg, sizeof( c->msg ), "<%s> could not read file", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return(1); } { @@ -1572,12 +1463,14 @@ config_generic(ConfigArgs *c) { { ServerID *si, **sip; LDAPURLDesc *lud; - int num = atoi( c->argv[1] ); - if ( num < 0 || num > SLAP_SYNC_SID_MAX ) { - snprintf( c->msg, sizeof( c->msg ), + int num; + if ( lutil_atoi( &num, c->argv[1] ) || + num < 0 || num > SLAP_SYNC_SID_MAX ) + { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> illegal server ID", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return 1; } /* only one value allowed if no URL is given */ @@ -1585,18 +1478,18 @@ config_generic(ConfigArgs *c) { int len; if ( sid_list && BER_BVISEMPTY( &sid_list->si_url )) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> only one server ID allowed now", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return 1; } if ( ldap_url_parse( c->argv[2], &lud )) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[2] ); + c->log, c->cr_msg, c->argv[2] ); return 1; } len = strlen( c->argv[2] ); @@ -1606,14 +1499,18 @@ config_generic(ConfigArgs *c) { strcpy( si->si_url.bv_val, c->argv[2] ); } else { if ( sid_list ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unqualified server ID not allowed now", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[1] ); + c->log, c->cr_msg, c->argv[1] ); return 1; } si = ch_malloc( sizeof(ServerID) ); + BER_BVZERO( &si->si_url ); slap_serverID = num; + Debug( LDAP_DEBUG_CONFIG, + "%s: SID=%d\n", + c->log, slap_serverID, 0 ); } si->si_next = NULL; si->si_num = num; @@ -1664,6 +1561,10 @@ config_generic(ConfigArgs *c) { ldap_free_urldesc( lu2 ); if ( isMe ) { slap_serverID = si->si_num; + Debug( LDAP_DEBUG_CONFIG, + "%s: SID=%d (listener=%s)\n", + c->log, slap_serverID, + l[i]->sl_url.bv_val ); break; } } @@ -1683,10 +1584,10 @@ config_generic(ConfigArgs *c) { case CFG_LASTMOD: if(SLAP_NOLASTMODCMD(c->be)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> not available for %s database", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> not available for %s database", c->argv[0], c->be->bd_info->bi_type ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(1); } if(c->value_int) @@ -1697,10 +1598,10 @@ config_generic(ConfigArgs *c) { case CFG_MIRRORMODE: if(!SLAP_SHADOW(c->be)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> database is not a shadow", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(1); } if(c->value_int) @@ -1725,9 +1626,9 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MAX: if (c->value_int < index_substr_if_minlen) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", - c->log, c->msg, c->value_int ); + c->log, c->cr_msg, c->value_int ); return(1); } index_substr_if_maxlen = c->value_int; @@ -1735,9 +1636,9 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MIN: if (c->value_int > index_substr_if_maxlen) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n", - c->log, c->msg, c->value_int ); + c->log, c->cr_msg, c->value_int ); return(1); } index_substr_if_minlen = c->value_int; @@ -1752,10 +1653,10 @@ config_generic(ConfigArgs *c) { modcur = c->private; /* This should never fail */ if ( module_path( modcur->mp_path.bv_val )) { - snprintf( c->msg, sizeof( c->msg ), "<%s> module path no longer valid", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> module path no longer valid", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", - c->log, c->msg, modcur->mp_path.bv_val ); + c->log, c->cr_msg, modcur->mp_path.bv_val ); return(1); } } @@ -1943,16 +1844,16 @@ config_passwd_hash(ConfigArgs *c) { } for(i = 1; i < c->argc; i++) { if(!lutil_passwd_scheme(c->argv[i])) { - snprintf( c->msg, sizeof( c->msg ), "<%s> scheme not available", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> scheme not available", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); } else { ldap_charray_add(&default_passwd_hash, c->argv[i]); } if(!default_passwd_hash) { - snprintf( c->msg, sizeof( c->msg ), "<%s> no valid hashes found", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> no valid hashes found", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(1); } } @@ -2012,9 +1913,9 @@ config_sizelimit(ConfigArgs *c) { if(!strncasecmp(c->argv[i], "size", 4)) { rc = limits_parse_one(c->argv[i], lim); if ( rc ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse value", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } } else { @@ -2022,9 +1923,9 @@ config_sizelimit(ConfigArgs *c) { lim->lms_s_soft = -1; } else { if ( lutil_atoix( &lim->lms_s_soft, c->argv[i], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse limit", c->argv[0]); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } } @@ -2059,9 +1960,9 @@ config_timelimit(ConfigArgs *c) { if(!strncasecmp(c->argv[i], "time", 4)) { rc = limits_parse_one(c->argv[i], lim); if ( rc ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse value", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } } else { @@ -2069,9 +1970,9 @@ config_timelimit(ConfigArgs *c) { lim->lms_t_soft = -1; } else { if ( lutil_atoix( &lim->lms_t_soft, c->argv[i], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse limit", c->argv[0]); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } } @@ -2219,10 +2120,10 @@ config_suffix(ConfigArgs *c) #ifdef SLAPD_MONITOR_DN if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> DN is reserved for monitoring slapd", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> DN is reserved for monitoring slapd", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", - c->log, c->msg, SLAPD_MONITOR_DN); + c->log, c->cr_msg, SLAPD_MONITOR_DN); return(1); } #endif @@ -2232,7 +2133,7 @@ config_suffix(ConfigArgs *c) if (SLAP_DBHIDDEN( c->be )) tbe = NULL; else - tbe = select_backend(&ndn, 0, 0); + tbe = select_backend(&ndn, 0); if(tbe == c->be) { Debug( LDAP_DEBUG_ANY, "%s: suffix already served by this backend!.\n", c->log, 0, 0); @@ -2253,11 +2154,11 @@ config_suffix(ConfigArgs *c) type = oi->oi_orig->bi_type; } - snprintf( c->msg, sizeof( c->msg ), "<%s> namingContext \"%s\" " + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> namingContext \"%s\" " "already served by a preceding %s database", c->argv[0], pdn.bv_val, type ); Debug(LDAP_DEBUG_ANY, "%s: %s serving namingContext \"%s\"\n", - c->log, c->msg, tbe->be_suffix[0].bv_val); + c->log, c->cr_msg, tbe->be_suffix[0].bv_val); free(pdn.bv_val); free(ndn.bv_val); return(1); @@ -2317,12 +2218,12 @@ config_rootpw(ConfigArgs *c) { return 0; } - tbe = select_backend(&c->be->be_rootndn, 0, 0); + tbe = select_backend(&c->be->be_rootndn, 0); if(tbe != c->be) { - snprintf( c->msg, sizeof( c->msg ), "<%s> can only be set when rootdn is under suffix", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> can only be set when rootdn is under suffix", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(1); } if ( !BER_BVISNULL( &c->be->be_rootpw )) @@ -2369,9 +2270,9 @@ config_restrict(ConfigArgs *c) { } i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops ); if ( i ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown operation", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown operation", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } if ( restrictops & SLAP_RESTRICT_OP_EXTENDED ) @@ -2405,9 +2306,9 @@ config_allows(ConfigArgs *c) { } i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows); if ( i ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown feature", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } global_allows |= allows; @@ -2438,9 +2339,9 @@ config_disallows(ConfigArgs *c) { } i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows); if ( i ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown feature", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } global_disallows |= disallows; @@ -2481,13 +2382,13 @@ config_requires(ConfigArgs *c) { i = verbs_to_mask(argc, argv, requires_ops, &requires); if ( i ) { if (strcasecmp( c->argv[ i ], "none" ) == 0 ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> \"none\" (#%d) must be listed first", c->argv[0], i - 1 ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> \"none\" (#%d) must be listed first", c->argv[0], i - 1 ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); } else { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 ); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); } return(1); } @@ -2560,8 +2461,7 @@ int slap_loglevel_get( struct berval *s, int *l ) { int rc; - unsigned long i; - slap_mask_t m; + slap_mask_t m, i; if ( loglevel_ops == NULL ) { loglevel_init(); @@ -2571,12 +2471,10 @@ slap_loglevel_get( struct berval *s, int *l ) m |= loglevel_ops[ i ].mask; } - m = ~m; - - for ( i = 1; i <= ( 1 << ( sizeof( int ) * 8 - 1 ) ) && !( m & i ); i <<= 1 ) + for ( i = 1; m & i; i <<= 1 ) ; - if ( !( m & i ) ) { + if ( i == 0 ) { return -1; } @@ -2696,27 +2594,29 @@ config_loglevel(ConfigArgs *c) { return 0; } - config_syslog = 0; - for( i=1; i < c->argc; i++ ) { int level; if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) { if( lutil_atoi( &level, c->argv[i] ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse level", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return( 1 ); } } else { if ( str2loglevel( c->argv[i], &level ) ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown level", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown level", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return( 1 ); } } - config_syslog |= level; + /* Explicitly setting a zero clears all the levels */ + if ( level ) + config_syslog |= level; + else + config_syslog = 0; } if ( slapMode & SLAP_SERVER_MODE ) { ldap_syslog = config_syslog; @@ -2747,9 +2647,9 @@ config_referral(ConfigArgs *c) { return 0; } if(validate_global_referral(c->argv[1])) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid URL", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", - c->log, c->msg, c->argv[1]); + c->log, c->cr_msg, c->argv[1]); return(1); } @@ -2817,16 +2717,16 @@ config_security(ConfigArgs *c) { } } if ( !tgt ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown factor", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown factor", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } if ( lutil_atou( tgt, src ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to parse factor", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse factor", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->argv[i]); + c->log, c->cr_msg, c->argv[i]); return(1); } } @@ -2849,230 +2749,6 @@ anlist_unparse( AttributeName *an, char *ptr, ber_len_t buflen ) { return ptr; } -static void -replica_unparse( struct slap_replica_info *ri, int i, struct berval *bv ) -{ - int len; - char *ptr; - struct berval bc = BER_BVNULL; - char numbuf[32]; - - assert( !BER_BVISNULL( &ri->ri_bindconf.sb_uri ) ); - - BER_BVZERO( bv ); - - len = snprintf(numbuf, sizeof( numbuf ), SLAP_X_ORDERED_FMT, i ); - if ( len >= sizeof( numbuf ) ) { - /* FIXME: how can indicate error? */ - return; - } - - if ( ri->ri_nsuffix ) { - for (i=0; !BER_BVISNULL( &ri->ri_nsuffix[i] ); i++) { - len += ri->ri_nsuffix[i].bv_len + STRLENOF(" suffix=\"\""); - } - } - if ( ri->ri_attrs ) { - len += STRLENOF(" attrs"); - if ( ri->ri_exclude ) len++; - for (i=0; !BER_BVISNULL( &ri->ri_attrs[i].an_name ); i++) { - len += 1 + ri->ri_attrs[i].an_name.bv_len; - } - } - bindconf_unparse( &ri->ri_bindconf, &bc ); - len += bc.bv_len; - - bv->bv_val = ch_malloc(len + 1); - bv->bv_len = len; - - ptr = lutil_strcopy( bv->bv_val, numbuf ); - - /* start with URI from bindconf */ - assert( !BER_BVISNULL( &bc ) ); - if ( bc.bv_val ) { - strcpy( ptr, bc.bv_val ); - ch_free( bc.bv_val ); - } - - if ( ri->ri_nsuffix ) { - for (i=0; !BER_BVISNULL( &ri->ri_nsuffix[i] ); i++) { - ptr = lutil_strcopy( ptr, " suffix=\"" ); - ptr = lutil_strcopy( ptr, ri->ri_nsuffix[i].bv_val ); - *ptr++ = '"'; - } - } - if ( ri->ri_attrs ) { - ptr = lutil_strcopy( ptr, " attrs" ); - if ( ri->ri_exclude ) *ptr++ = '!'; - *ptr++ = '='; - ptr = anlist_unparse( ri->ri_attrs, ptr, 0 ); - } -} - -static int -config_replica(ConfigArgs *c) { - int i, nr = -1; - char *replicahost = NULL, *replicauri = NULL; - LDAPURLDesc *ludp; - - if (c->op == SLAP_CONFIG_EMIT) { - if (c->be->be_replica) { - struct berval bv; - for (i=0;c->be->be_replica[i]; i++) { - replica_unparse( c->be->be_replica[i], i, &bv ); - ber_bvarray_add( &c->rvalue_vals, &bv ); - } - return 0; - } - return 1; - } else if ( c->op == LDAP_MOD_DELETE ) { - /* FIXME: there is no replica_free function */ - if ( c->valx < 0 ) { - } else { - } - } - if(SLAP_MONITOR(c->be)) { - Debug(LDAP_DEBUG_ANY, "%s: " - "\"replica\" should not be used inside monitor database\n", - c->log, 0, 0); - return(0); /* FIXME: should this be an error? */ - } - - for(i = 1; i < c->argc; i++) { - if(!strncasecmp(c->argv[i], "host=", STRLENOF("host="))) { - ber_len_t len; - - if ( replicauri ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> replica host/URI already specified", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->msg, replicauri ); - return(1); - } - - replicahost = c->argv[i] + STRLENOF("host="); - len = strlen( replicahost ) + STRLENOF("ldap://"); - replicauri = ch_malloc( len + 1 ); - snprintf( replicauri, len + 1, "ldap://%s", replicahost ); - replicahost = replicauri + STRLENOF( "ldap://"); - nr = add_replica_info(c->be, replicauri, replicahost); - break; - } else if(!strncasecmp(c->argv[i], "uri=", STRLENOF("uri="))) { - ber_len_t len; - - if ( replicauri ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> replica host/URI already specified", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->msg, replicauri ); - return(1); - } - - if(ldap_url_parse(c->argv[i] + STRLENOF("uri="), &ludp) != LDAP_SUCCESS) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid uri", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); - return(1); - } - if(!ludp->lud_host) { - ldap_free_urldesc(ludp); - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid uri - missing hostname", - c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); - return(1); - } - - len = strlen(ludp->lud_scheme) + strlen(ludp->lud_host) + - STRLENOF("://") + 1; - if (ludp->lud_port != LDAP_PORT) { - if (ludp->lud_port < 1 || ludp->lud_port > 65535) { - ldap_free_urldesc(ludp); - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid port", - c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); - return(1); - } - len += STRLENOF(":65535"); - } - replicauri = ch_malloc( len ); - replicahost = lutil_strcopy( replicauri, ludp->lud_scheme ); - replicahost = lutil_strcopy( replicahost, "://" ); - if (ludp->lud_port == LDAP_PORT) { - strcpy( replicahost, ludp->lud_host ); - } else { - sprintf( replicahost, "%s:%d",ludp->lud_host,ludp->lud_port ); - } - ldap_free_urldesc(ludp); - nr = add_replica_info(c->be, replicauri, replicahost); - break; - } - } - if(i == c->argc) { - snprintf( c->msg, sizeof( c->msg ), "<%s> missing host or uri", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); - return(1); - } else if(nr == -1) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unable to add replica", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", c->log, c->msg, - replicauri ? replicauri : "" ); - return(1); - } else { - for(i = 1; i < c->argc; i++) { - if(!strncasecmp(c->argv[i], "uri=", STRLENOF("uri="))) { - /* dealt with separately; don't let it get to bindconf */ - ; - - } else if(!strncasecmp(c->argv[i], "host=", STRLENOF("host="))) { - /* dealt with separately; don't let it get to bindconf */ - ; - - } else if(!strncasecmp(c->argv[i], "suffix=", STRLENOF( "suffix="))) { - switch(add_replica_suffix(c->be, nr, c->argv[i] + STRLENOF("suffix="))) { - case 1: - Debug( LDAP_DEBUG_ANY, "%s: " - "suffix \"%s\" in \"replica\" line is not valid for backend.\n", - c->log, c->argv[i] + STRLENOF("suffix="), 0); - return 1; - break; - case 2: - Debug( LDAP_DEBUG_ANY, "%s: " - "unable to normalize suffix in \"replica\" line.\n", - c->log, 0, 0); - return 1; - break; - } - - } else if (!strncasecmp(c->argv[i], "attr", STRLENOF("attr")) - || !strncasecmp(c->argv[i], "attrs", STRLENOF("attrs"))) - { - int exclude = 0; - char *arg = c->argv[i] + STRLENOF("attr"); - if (arg[0] == 's') { - arg++; - } else { - Debug( LDAP_DEBUG_ANY, - "%s: \"attr\" " - "is deprecated (and undocumented); " - "use \"attrs\" instead.\n", - c->log, 0, 0 ); - } - if(arg[0] == '!') { - arg++; - exclude = 1; - } - if(arg[0] != '=') { - continue; - } - if(add_replica_attrs(c->be, nr, arg + 1, exclude)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> unknown attribute", c->argv[0] ); - Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, arg + 1); - return(1); - } - } else if ( bindconf_parse( c->argv[i], - &c->be->be_replica[nr]->ri_bindconf ) ) { - return(1); - } - } - } - return(0); -} - static int config_updatedn(ConfigArgs *c) { if (c->op == SLAP_CONFIG_EMIT) { @@ -3089,9 +2765,9 @@ config_updatedn(ConfigArgs *c) { return 0; } if(SLAP_SHADOW(c->be)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> database already shadowed", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database already shadowed", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(1); } @@ -3151,17 +2827,17 @@ config_updateref(ConfigArgs *c) { return 0; } if(!SLAP_SHADOW(c->be) && !c->be->be_syncinfo) { - snprintf( c->msg, sizeof( c->msg ), "<%s> must appear after syncrepl or updatedn", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must appear after syncrepl or updatedn", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(1); } if(validate_global_referral(c->argv[1])) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid URL", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] ); Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", - c->log, c->msg, c->argv[1]); + c->log, c->cr_msg, c->argv[1]); return(1); } ber_str2bv(c->argv[1], 0, 0, &val); @@ -3169,6 +2845,17 @@ config_updateref(ConfigArgs *c) { return(0); } +static int +config_obsolete(ConfigArgs *c) { + if (c->op == SLAP_CONFIG_EMIT) + return 1; + + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> keyword is obsolete (ignored)", + c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0); + return(0); +} + static int config_include(ConfigArgs *c) { int savelineno = c->lineno; @@ -3214,6 +2901,9 @@ config_tls_option(ConfigArgs *c) { case CFG_TLS_CA_PATH: flag = LDAP_OPT_X_TLS_CACERTDIR; break; case CFG_TLS_CA_FILE: flag = LDAP_OPT_X_TLS_CACERTFILE; break; case CFG_TLS_DH_FILE: flag = LDAP_OPT_X_TLS_DHFILE; break; +#ifdef HAVE_GNUTLS + case CFG_TLS_CRL_FILE: flag = LDAP_OPT_X_TLS_CRLFILE; break; +#endif default: Debug(LDAP_DEBUG_ANY, "%s: " "unknown tls_option <0x%x>\n", c->log, c->type, 0); @@ -3374,7 +3064,7 @@ ok: rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL, NULL ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "config error processing %s: %s\n", - rs->sr_entry->e_name.bv_val, sc->ca->msg, 0 ); + rs->sr_entry->e_name.bv_val, sc->ca->cr_msg, 0 ); } } return rs->sr_err; @@ -3410,7 +3100,7 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { if ( !cfb->cb_db.bd_info ) return 0; /* FIXME: eventually this will be a fatal error */ - if ( backend_db_init( "ldif", &cfb->cb_db, -1 ) == NULL ) + if ( backend_db_init( "ldif", &cfb->cb_db, -1, NULL ) == NULL ) return 1; cfb->cb_db.be_suffix = be->be_suffix; @@ -3431,6 +3121,9 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { argv[1] = (char *)dir; argv[2] = NULL; c.argv = argv; + c.reply.err = 0; + c.reply.msg[0] = 0; + c.table = Cft_Database; ct = config_find_keyword( c.be->be_cf_ocs->co_table, &c ); if ( !ct ) @@ -3439,15 +3132,15 @@ config_setup_ldif( BackendDB *be, const char *dir, int readit ) { if ( config_add_vals( ct, &c )) return 1; - if ( backend_startup_one( &cfb->cb_db )) + if ( backend_startup_one( &cfb->cb_db, &c.reply )) return 1; if ( readit ) { void *thrctx = ldap_pvt_thread_pool_context(); int prev_DN_strict; - op = (Operation *) &opbuf; - connection_fake_init( &conn, op, thrctx ); + connection_fake_init( &conn, &opbuf, thrctx ); + op = &opbuf.ob_op; filter.f_desc = slap_schema.si_ad_objectClass; @@ -3546,7 +3239,7 @@ read_config(const char *fname, const char *dir) { int rc; /* Setup the config backend */ - be = backend_db_init( "config", NULL, 0 ); + be = backend_db_init( "config", NULL, 0, NULL ); if ( !be ) return 1; @@ -3627,7 +3320,7 @@ done: static int config_back_bind( Operation *op, SlapReply *rs ) { - if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op )) { + if ( be_isroot_pw( op ) ) { ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd )); /* frontend sends result */ return LDAP_SUCCESS; @@ -3667,14 +3360,17 @@ config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth ) } static ConfigTable * -config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad ) +config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad, + ConfigArgs *ca ) { int i, j; for (j=0; jco_table[i].name; i++) - if ( colst[j]->co_table[i].ad == ad ) + if ( colst[j]->co_table[i].ad == ad ) { + ca->table = colst[j]->co_type; return &colst[j]->co_table[i]; + } } return NULL; } @@ -3759,7 +3455,7 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr ) if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) { rc = ordered_value_sort( a, 1 ); if ( rc ) { - snprintf(ca->msg, sizeof( ca->msg ), "ordered_value_sort failed on attr %s\n", + snprintf(ca->cr_msg, sizeof( ca->cr_msg ), "ordered_value_sort failed on attr %s\n", ad->ad_cname.bv_val ); return rc; } @@ -3953,7 +3649,7 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, { CfEntryInfo *ce; int index = -1, gotindex = 0, nsibs, rc = 0; - int renumber = 0, tailindex = 0, isfrontend = 0; + int renumber = 0, tailindex = 0, isfrontend = 0, isconfig = 0; char *ptr1, *ptr2 = NULL; struct berval rdn; @@ -3968,9 +3664,14 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, /* See if the rdn has an index already */ dnRdn( &e->e_name, &rdn ); - if ( ce_type == Cft_Database && !strncmp( rdn.bv_val + rdn.bv_len - - STRLENOF("frontend"), "frontend", STRLENOF("frontend") )) - isfrontend = 1; + if ( ce_type == Cft_Database ) { + if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("frontend"), + "frontend", STRLENOF("frontend") )) + isfrontend = 1; + else if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("config"), + "config", STRLENOF("config") )) + isconfig = 1; + } ptr1 = ber_bvchr( &e->e_name, '{' ); if ( ptr1 && ptr1 - e->e_name.bv_val < rdn.bv_len ) { char *next; @@ -3989,6 +3690,9 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, if ( index != -1 || !isfrontend ) return LDAP_NAMING_VIOLATION; } + if ( isconfig && index != 0 ){ + return LDAP_NAMING_VIOLATION; + } } /* count related kids */ @@ -4009,6 +3713,10 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, renumber = 1; } } + /* config DB is always "0" */ + if ( isconfig && index == -1 ) { + index = 0; + } if ( !isfrontend && index == -1 ) { index = nsibs; } @@ -4023,32 +3731,65 @@ check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e, return rc; } +static int +count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs ) +{ + ConfigOCs co, *cop; + ObjectClass **sups; + + co.co_name = &oc->soc_cname; + cop = avl_find( CfOcTree, &co, CfOc_cmp ); + if ( cop ) { + int i; + + /* check for duplicates */ + for ( i = 0; i < *nocs; i++ ) { + if ( *copp && (*copp)[i] == cop ) { + break; + } + } + + if ( i == *nocs ) { + ConfigOCs **tmp = ch_realloc( *copp, (*nocs + 1)*sizeof( ConfigOCs * ) ); + if ( tmp == NULL ) { + return -1; + } + *copp = tmp; + (*copp)[*nocs] = cop; + (*nocs)++; + } + } + + for ( sups = oc->soc_sups; sups && *sups; sups++ ) { + if ( count_oc( *sups, copp, nocs ) ) { + return -1; + } + } + + return 0; +} + static ConfigOCs ** count_ocs( Attribute *oc_at, int *nocs ) { - int i, j, n; - ConfigOCs co, *coptr, **colst; + int i; + ConfigOCs **colst = NULL; - /* count the objectclasses */ - for ( i=0; oc_at->a_nvals[i].bv_val; i++ ); - n = i; - colst = (ConfigOCs **)ch_malloc( n * sizeof(ConfigOCs *)); + *nocs = 0; - for ( i=0, j=0; ia_nvals[i]; - coptr = avl_find( CfOcTree, &co, CfOc_cmp ); - - /* ignore non-config objectclasses. probably should be - * an error, general data doesn't belong here. - */ - if ( !coptr ) continue; + for ( i = 0; !BER_BVISNULL( &oc_at->a_nvals[i] ); i++ ) + /* count attrs */ ; - /* Ignore the root objectclass, it has no implementation. - */ - if ( coptr->co_type == Cft_Abstract ) continue; - colst[j++] = coptr; + for ( ; i--; ) { + ObjectClass *oc = oc_bvfind( &oc_at->a_nvals[i] ); + + assert( oc != NULL ); + if ( count_oc( oc, &colst, nocs ) ) { + ch_free( colst ); + return NULL; + } } - *nocs = j; + return colst; } @@ -4077,8 +3818,9 @@ cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) static int cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) { - if ( p->ce_type != Cft_Global ) + if ( p->ce_type != Cft_Global ) { return LDAP_CONSTRAINT_VIOLATION; + } ca->be = frontendDB; /* just to get past check_vals */ return LDAP_SUCCESS; } @@ -4086,24 +3828,27 @@ cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) static int cfAddBackend( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) { - if ( p->ce_type != Cft_Global ) + if ( p->ce_type != Cft_Global ) { return LDAP_CONSTRAINT_VIOLATION; + } return LDAP_SUCCESS; } static int cfAddModule( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) { - if ( p->ce_type != Cft_Global ) + if ( p->ce_type != Cft_Global ) { return LDAP_CONSTRAINT_VIOLATION; + } return LDAP_SUCCESS; } static int cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca ) { - if ( p->ce_type != Cft_Database ) + if ( p->ce_type != Cft_Database ) { return LDAP_CONSTRAINT_VIOLATION; + } ca->be = p->ce_be; return LDAP_SUCCESS; } @@ -4123,28 +3868,28 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs, struct berval bv = BER_BVC("olcDitContentRules"); ad = NULL; slap_bv2ad( &bv, &ad, &text ); - ct = config_find_table( colst, nocs, ad ); + ct = config_find_table( colst, nocs, ad, ca ); config_del_vals( ct, ca ); } if ( cfn->c_oc_head ) { struct berval bv = BER_BVC("olcObjectClasses"); ad = NULL; slap_bv2ad( &bv, &ad, &text ); - ct = config_find_table( colst, nocs, ad ); + ct = config_find_table( colst, nocs, ad, ca ); config_del_vals( ct, ca ); } if ( cfn->c_at_head ) { struct berval bv = BER_BVC("olcAttributeTypes"); ad = NULL; slap_bv2ad( &bv, &ad, &text ); - ct = config_find_table( colst, nocs, ad ); + ct = config_find_table( colst, nocs, ad, ca ); config_del_vals( ct, ca ); } if ( cfn->c_om_head ) { struct berval bv = BER_BVC("olcObjectIdentifier"); ad = NULL; slap_bv2ad( &bv, &ad, &text ); - ct = config_find_table( colst, nocs, ad ); + ct = config_find_table( colst, nocs, ad, ca ); config_del_vals( ct, ca ); } cfo = p->ce_private; @@ -4152,18 +3897,49 @@ schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs, ch_free( cfn ); } +static int +config_add_oc( ConfigOCs **cop, CfEntryInfo *last, Entry *e, ConfigArgs *ca ) +{ + int rc = LDAP_CONSTRAINT_VIOLATION; + ObjectClass **ocp; + + if ( (*cop)->co_ldadd ) { + rc = (*cop)->co_ldadd( last, e, ca ); + if ( rc != LDAP_CONSTRAINT_VIOLATION ) { + return rc; + } + } + + for ( ocp = (*cop)->co_oc->soc_sups; ocp && *ocp; ocp++ ) { + ConfigOCs co = { 0 }; + + co.co_name = &(*ocp)->soc_cname; + *cop = avl_find( CfOcTree, &co, CfOc_cmp ); + if ( *cop == NULL ) { + return rc; + } + + rc = config_add_oc( cop, last, e, ca ); + if ( rc != LDAP_CONSTRAINT_VIOLATION ) { + return rc; + } + } + + return rc; +} + /* Parse an LDAP entry into config directives */ static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, int *renum, Operation *op ) { - CfEntryInfo *ce, *last; - ConfigOCs **colst; - Attribute *a, *oc_at; - int i, ibase = -1, nocs, rc = 0; - struct berval pdn; - ConfigTable *ct; - char *ptr; + CfEntryInfo *ce, *last = NULL; + ConfigOCs co, *coptr, **colst; + Attribute *a, *oc_at, *soc_at; + int i, ibase = -1, nocs, rc = 0; + struct berval pdn; + ConfigTable *ct; + char *ptr, *log_prefix = op ? op->o_log_prefix : ""; memset( ca, 0, sizeof(ConfigArgs)); @@ -4173,10 +3949,15 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, */ ce = config_find_base( cfb->cb_root, &e->e_nname, &last ); if ( ce ) { - if (( op && op->o_managedsait ) || + if ( ( op && op->o_managedsait ) || ( ce->ce_type != Cft_Database && ce->ce_type != Cft_Overlay && - ce->ce_type != Cft_Module )) - return LDAP_ALREADY_EXISTS; + ce->ce_type != Cft_Module ) ) + { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" already exists\n", + log_prefix, e->e_name.bv_val, 0 ); + return LDAP_ALREADY_EXISTS; + } } dnParent( &e->e_nname, &pdn ); @@ -4184,23 +3965,73 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, /* If last is NULL, the new entry is the root/suffix entry, * otherwise last should be the parent. */ - if ( last && !dn_match( &last->ce_entry->e_nname, &pdn )) { - if ( rs ) + if ( last && !dn_match( &last->ce_entry->e_nname, &pdn ) ) { + if ( rs ) { rs->sr_matched = last->ce_entry->e_name.bv_val; + } + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" not child of DN=\"%s\"\n", + log_prefix, e->e_name.bv_val, + last->ce_entry->e_name.bv_val ); return LDAP_NO_SUCH_OBJECT; } if ( op ) { /* No parent, must be root. This will never happen... */ - if ( !last && !be_isroot( op ) && !be_shadow_update( op )) + if ( !last && !be_isroot( op ) && !be_shadow_update( op ) ) { return LDAP_NO_SUCH_OBJECT; + } + if ( last && !access_allowed( op, last->ce_entry, - slap_schema.si_ad_children, NULL, ACL_WADD, NULL )) + slap_schema.si_ad_children, NULL, ACL_WADD, NULL ) ) + { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no write access to \"children\" of parent\n", + log_prefix, e->e_name.bv_val, 0 ); return LDAP_INSUFFICIENT_ACCESS; + } } oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); - if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION; + if ( !oc_at ) { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no objectClass\n", + log_prefix, e->e_name.bv_val, 0 ); + return LDAP_OBJECT_CLASS_VIOLATION; + } + + soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass ); + if ( !soc_at ) { + ObjectClass *soc = NULL; + char textbuf[ SLAP_TEXT_BUFLEN ]; + const char *text = textbuf; + + /* FIXME: check result */ + rc = structural_class( oc_at->a_nvals, &soc, NULL, + &text, textbuf, sizeof(textbuf), NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no structural objectClass (%s)\n", + log_prefix, e->e_name.bv_val, text ); + return rc; + } + attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &soc->soc_cname, NULL ); + soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass ); + if ( soc_at == NULL ) { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no structural objectClass; " + "unable to merge computed class %s\n", + log_prefix, e->e_name.bv_val, + soc->soc_cname.bv_val ); + return LDAP_OBJECT_CLASS_VIOLATION; + } + + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no structural objectClass; " + "computed objectClass %s merged\n", + log_prefix, e->e_name.bv_val, + soc->soc_cname.bv_val ); + } /* Fake the coordinates based on whether we're part of an * LDAP Add or if reading the config dir @@ -4214,13 +4045,20 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, } ca->ca_op = op; - colst = count_ocs( oc_at, &nocs ); + co.co_name = &soc_at->a_nvals[0]; + coptr = avl_find( CfOcTree, &co, CfOc_cmp ); + if ( coptr == NULL ) { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no structural objectClass in configuration table\n", + log_prefix, e->e_name.bv_val, 0 ); + return LDAP_OBJECT_CLASS_VIOLATION; + } /* Only the root can be Cft_Global, everything else must * have a parent. Only limited nesting arrangements are allowed. */ rc = LDAP_CONSTRAINT_VIOLATION; - if ( colst[0]->co_type == Cft_Global && !last ) { + if ( coptr->co_type == Cft_Global && !last ) { cfn = cfb->cb_config; ca->private = cfn; ca->be = frontendDB; /* just to get past check_vals */ @@ -4231,15 +4069,17 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, * any necessary arg setup */ if ( last ) { - for ( i=0; ico_ldadd && - ( rc = colst[i]->co_ldadd( last, e, ca )) - != LDAP_CONSTRAINT_VIOLATION ) { - break; - } + rc = config_add_oc( &coptr, last, e, ca ); + if ( rc == LDAP_CONSTRAINT_VIOLATION ) { + Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: " + "DN=\"%s\" no structural objectClass add function\n", + log_prefix, e->e_name.bv_val, 0 ); + return LDAP_OBJECT_CLASS_VIOLATION; } } + colst = count_ocs( oc_at, &nocs ); + /* Add the entry but don't parse it, we already have its contents */ if ( rc == LDAP_COMPARE_TRUE ) { rc = LDAP_SUCCESS; @@ -4266,14 +4106,15 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, * but only the other types support auto-renumbering of siblings. */ { - rc = check_name_index( last, colst[0]->co_type, e, rs, renum, + rc = check_name_index( last, coptr->co_type, e, rs, renum, &ibase ); if ( rc ) { goto done_noop; } - if ( renum && *renum && colst[0]->co_type != Cft_Database && - colst[0]->co_type != Cft_Overlay ) { - snprintf( ca->msg, sizeof( ca->msg ), + if ( renum && *renum && coptr->co_type != Cft_Database && + coptr->co_type != Cft_Overlay ) + { + snprintf( ca->cr_msg, sizeof( ca->cr_msg ), "operation requires sibling renumbering" ); rc = LDAP_UNWILLING_TO_PERFORM; goto done_noop; @@ -4285,9 +4126,9 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, /* Make sure we process attrs in the required order */ sort_attrs( e, colst, nocs ); - for ( a=e->e_attrs; a; a=a->a_next ) { + for ( a = e->e_attrs; a; a = a->a_next ) { if ( a == oc_at ) continue; - ct = config_find_table( colst, nocs, a->a_desc ); + ct = config_find_table( colst, nocs, a->a_desc, ca ); if ( !ct ) continue; /* user data? */ rc = check_vals( ct, ca, a, 1 ); if ( rc ) goto done_noop; @@ -4296,7 +4137,7 @@ config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs, /* Basic syntax checks are OK. Do the actual settings. */ for ( a=e->e_attrs; a; a=a->a_next ) { if ( a == oc_at ) continue; - ct = config_find_table( colst, nocs, a->a_desc ); + ct = config_find_table( colst, nocs, a->a_desc, ca ); if ( !ct ) continue; /* user data? */ for (i=0; a->a_vals[i].bv_val; i++) { char *iptr = NULL; @@ -4328,20 +4169,22 @@ ok: /* Newly added databases and overlays need to be started up */ if ( CONFIG_ONLINE_ADD( ca )) { if ( colst[0]->co_type == Cft_Database ) { - rc = backend_startup_one( ca->be ); + rc = backend_startup_one( ca->be, &ca->reply ); } else if ( colst[0]->co_type == Cft_Overlay ) { if ( ca->bi->bi_db_open ) { BackendInfo *bi_orig = ca->be->bd_info; ca->be->bd_info = ca->bi; - rc = ca->bi->bi_db_open( ca->be ); + rc = ca->bi->bi_db_open( ca->be, &ca->reply ); ca->be->bd_info = bi_orig; } } if ( rc ) { - snprintf( ca->msg, sizeof( ca->msg ), "<%s> failed startup", ca->argv[0] ); + if (ca->cr_msg[0] == '\0') + snprintf( ca->cr_msg, sizeof( ca->cr_msg ), "<%s> failed startup", ca->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n", - ca->log, ca->msg, ca->argv[1] ); + ca->log, ca->cr_msg, ca->argv[1] ); rc = LDAP_OTHER; goto done; } @@ -4529,7 +4372,7 @@ config_back_add( Operation *op, SlapReply *rs ) */ rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber, op ); if ( rs->sr_err != LDAP_SUCCESS ) { - rs->sr_text = ca.msg; + rs->sr_text = ca.cr_msg; goto out2; } @@ -4645,7 +4488,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, strcpy( ca->log, "back-config" ); for (ml = op->orm_modlist; ml; ml=ml->sml_next) { - ct = config_find_table( colst, nocs, ml->sml_desc ); + ct = config_find_table( colst, nocs, ml->sml_desc, ca ); switch (ml->sml_op) { case LDAP_MOD_DELETE: case LDAP_MOD_REPLACE: { @@ -4653,7 +4496,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, int *idx = NULL; if ( ct && ( ct->arg_type & ARG_NO_DELETE )) { rc = LDAP_OTHER; - snprintf(ca->msg, sizeof(ca->msg), "cannot delete %s", + snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot delete %s", ml->sml_desc->ad_cname.bv_val ); goto out_noop; } @@ -4682,7 +4525,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, } rc = modify_delete_vindex(e, &ml->sml_mod, get_permissiveModify(op), - &rs->sr_text, ca->msg, sizeof(ca->msg), idx ); + &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg), idx ); if ( ml->sml_op == LDAP_MOD_REPLACE ) { ml->sml_values = vals; ml->sml_nvalues = nvals; @@ -4715,7 +4558,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, j = strtol( val, &next, 0 ); if ( next == val || next[ 0 ] != '}' || j < navals ) { rc = LDAP_OTHER; - snprintf(ca->msg, sizeof(ca->msg), "cannot insert %s", + snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot insert %s", ml->sml_desc->ad_cname.bv_val ); goto out_noop; } @@ -4726,7 +4569,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, } rc = modify_add_values(e, &ml->sml_mod, get_permissiveModify(op), - &rs->sr_text, ca->msg, sizeof(ca->msg) ); + &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) ); /* If value already exists, show success here * and ignore this operation down below. @@ -4753,12 +4596,12 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, if ( rc == LDAP_SUCCESS) { /* check that the entry still obeys the schema */ rc = entry_schema_check(op, e, NULL, 0, 0, - &rs->sr_text, ca->msg, sizeof(ca->msg) ); + &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) ); if ( rc ) goto out_noop; } /* Basic syntax checks are OK. Do the actual settings. */ for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { - ct = config_find_table( colst, nocs, ml->sml_desc ); + ct = config_find_table( colst, nocs, ml->sml_desc, ca ); if ( !ct ) continue; s = attr_find( save_attrs, ml->sml_desc ); @@ -4850,7 +4693,7 @@ out: for ( s = save_attrs; s; s = s->a_next ) { if ( s->a_flags & SLAP_ATTR_IXDEL ) { s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD); - ct = config_find_table( colst, nocs, s->a_desc ); + ct = config_find_table( colst, nocs, s->a_desc, ca ); a = attr_find( e->e_attrs, s->a_desc ); if ( a ) { /* clear the flag so the add check below will skip it */ @@ -4868,7 +4711,7 @@ out: } for ( a = e->e_attrs; a; a = a->a_next ) { if ( a->a_flags & SLAP_ATTR_IXADD ) { - ct = config_find_table( colst, nocs, a->a_desc ); + ct = config_find_table( colst, nocs, a->a_desc, ca ); ca->valx = -1; ca->line = NULL; config_del_vals( ct, ca ); @@ -4960,7 +4803,7 @@ config_back_modify( Operation *op, SlapReply *rs ) */ rs->sr_err = config_modify_internal( ce, op, rs, &ca ); if ( rs->sr_err ) { - rs->sr_text = ca.msg; + rs->sr_text = ca.cr_msg; } else if ( cfb->cb_use_ldif ) { BackendDB *be = op->o_bd; slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp; @@ -5364,6 +5207,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, attr_merge_normalize_one(e, ad, &val, NULL ); oc = main->co_oc; + c->table = main->co_type; if ( oc->soc_required ) config_build_attrs( e, oc->soc_required, ad, main->co_table, c ); @@ -5372,6 +5216,7 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, if ( extra ) { oc = extra->co_oc; + c->table = extra->co_type; if ( oc->soc_required ) config_build_attrs( e, oc->soc_required, ad, extra->co_table, c ); @@ -5380,8 +5225,8 @@ config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent, } oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); - rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->msg, - sizeof(c->msg), op ? op->o_tmpmemctx : NULL ); + rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg, + sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL ); attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL ); if ( op && !op->o_noop ) { op->ora_e = e; @@ -5413,7 +5258,10 @@ config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent, struct berval bv; for (; cf; cf=cf->c_sibs, c->depth++) { + if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head && + !cf->c_om_head ) continue; c->value_dn.bv_val = c->log; + LUTIL_SLASHPATH( cf->c_file.bv_val ); bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]); if ( !bv.bv_val ) { bv = cf->c_file; @@ -5559,7 +5407,7 @@ static const char *defacl[] = { }; static int -config_back_db_open( BackendDB *be ) +config_back_db_open( BackendDB *be, ConfigReply *cr ) { CfBackInfo *cfb = be->be_private; struct berval rdn; @@ -5585,8 +5433,8 @@ config_back_db_open( BackendDB *be ) } thrctx = ldap_pvt_thread_pool_context(); - op = (Operation *) &opbuf; - connection_fake_init( &conn, op, thrctx ); + connection_fake_init( &conn, &opbuf, thrctx ); + op = &opbuf.ob_op; op->o_tag = LDAP_REQ_ADD; op->o_callback = &cb; @@ -5797,7 +5645,7 @@ cfb_free_entries( CfEntryInfo *ce ) } static int -config_back_db_close( BackendDB *be ) +config_back_db_close( BackendDB *be, ConfigReply *cr ) { CfBackInfo *cfb = be->be_private; @@ -5812,7 +5660,7 @@ config_back_db_close( BackendDB *be ) } static int -config_back_db_destroy( BackendDB *be ) +config_back_db_destroy( BackendDB *be, ConfigReply *cr ) { CfBackInfo *cfb = be->be_private; @@ -5837,7 +5685,7 @@ config_back_db_destroy( BackendDB *be ) } static int -config_back_db_init( BackendDB *be ) +config_back_db_init( BackendDB *be, ConfigReply* cr ) { struct berval dn; CfBackInfo *cfb; @@ -5928,13 +5776,124 @@ config_tool_entry_get( BackendDB *be, ID id ) return NULL; } +static int entry_put_got_frontend=0; +static int entry_put_got_config=0; static ID config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) { CfBackInfo *cfb = be->be_private; BackendInfo *bi = cfb->cb_db.bd_info; + int rc; + struct berval rdn, vals[ 2 ]; ConfigArgs ca; + OperationBuffer opbuf; + Entry *ce; + Connection conn = {0}; + Operation *op = NULL; + void *thrctx; + + /* Create entry for frontend database if it does not exist already */ + if ( !entry_put_got_frontend ) { + if ( !strncmp( e->e_nname.bv_val, "olcDatabase", + STRLENOF( "olcDatabase" ))) { + if ( strncmp( e->e_nname.bv_val + + STRLENOF( "olcDatabase" ), "={-1}frontend", + STRLENOF( "={-1}frontend" )) && + strncmp( e->e_nname.bv_val + + STRLENOF( "olcDatabase" ), "=frontend", + STRLENOF( "=frontend" ))) { + vals[1].bv_len = 0; + vals[1].bv_val = NULL; + memset( &ca, 0, sizeof(ConfigArgs)); + ca.be = frontendDB; + ca.bi = frontendDB->bd_info; + ca.be->be_cf_ocs = &CFOC_FRONTEND; + rdn.bv_val = ca.log; + rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ), + "%s=" SLAP_X_ORDERED_FMT "%s", + cfAd_database->ad_cname.bv_val, -1, + ca.bi->bi_type); + ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn, + &CFOC_DATABASE, ca.be->be_cf_ocs ); + thrctx = ldap_pvt_thread_pool_context(); + connection_fake_init2( &conn, &opbuf, thrctx,0 ); + op = &opbuf.ob_op; + op->o_bd = &cfb->cb_db; + op->o_tag = LDAP_REQ_ADD; + op->ora_e = ce; + op->o_dn = be->be_rootdn; + op->o_ndn = be->be_rootndn; + rc = slap_add_opattrs(op, NULL, NULL, 0, 0); + if ( rc != LDAP_SUCCESS ) { + text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed"; + text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed"); + return NOID; + } + if ( ce && bi && bi->bi_tool_entry_put && + bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) { + entry_put_got_frontend++; + } else { + text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed"; + text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed"); + return NOID; + } + } else { + entry_put_got_frontend++; + } + } + } + /* Create entry for config database if it does not exist already */ + if ( !entry_put_got_config ) { + if ( !strncmp( e->e_nname.bv_val, "olcDatabase", + STRLENOF( "olcDatabase" ))) { + if ( strncmp( e->e_nname.bv_val + + STRLENOF( "olcDatabase" ), "={0}config", + STRLENOF( "={0}config" )) && + strncmp( e->e_nname.bv_val + + STRLENOF( "olcDatabase" ), "=config", + STRLENOF( "=config" )) ) { + vals[1].bv_len = 0; + vals[1].bv_val = NULL; + memset( &ca, 0, sizeof(ConfigArgs)); + ca.be = LDAP_STAILQ_FIRST( &backendDB ); + ca.bi = ca.be->bd_info; + rdn.bv_val = ca.log; + rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ), + "%s=" SLAP_X_ORDERED_FMT "%s", + cfAd_database->ad_cname.bv_val, 0, + ca.bi->bi_type); + ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn, &CFOC_DATABASE, + ca.be->be_cf_ocs ); + if ( ! op ) { + thrctx = ldap_pvt_thread_pool_context(); + connection_fake_init2( &conn, &opbuf, thrctx,0 ); + op = &opbuf.ob_op; + op->o_bd = &cfb->cb_db; + op->o_tag = LDAP_REQ_ADD; + op->o_dn = be->be_rootdn; + op->o_ndn = be->be_rootndn; + } + op->ora_e = ce; + rc = slap_add_opattrs(op, NULL, NULL, 0, 0); + if ( rc != LDAP_SUCCESS ) { + text->bv_val = "autocreation of \"olcDatabase={0}config\" failed"; + text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed"); + return NOID; + } + if (ce && bi && bi->bi_tool_entry_put && + bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) { + entry_put_got_config++; + } else { + text->bv_val = "autocreation of \"olcDatabase={0}config\" failed"; + text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed"); + return NOID; + } + } else { + entry_put_got_config++; + } + } + } if ( bi && bi->bi_tool_entry_put && config_add_internal( cfb, e, &ca, NULL, NULL, NULL ) == 0 ) return bi->bi_tool_entry_put( &cfb->cb_db, e, text ); diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 706cc43559..6b76332a5c 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -46,10 +46,11 @@ do_bind( ber_tag_t tag; Backend *be = NULL; - Debug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_bind\n", + op->o_log_prefix, 0, 0 ); /* - * Force to connection to "anonymous" until bind succeeds. + * Force the connection to "anonymous" until bind succeeds. */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if ( op->o_conn->c_sasl_bind_in_progress ) { @@ -101,7 +102,8 @@ do_bind( tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method ); if ( tag == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "bind: ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; @@ -134,13 +136,16 @@ do_bind( } if ( tag == LBER_ERROR ) { + Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_bind: get_ctrls failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_bind: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); goto cleanup; } @@ -151,14 +156,18 @@ do_bind( rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "bind: invalid dn (%s)\n", - dn.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_bind: invalid dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } + Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n", + op->o_log_prefix, op->o_req_dn.bv_val, + (unsigned long) op->orb_method, 0, 0 ); + if( op->orb_method == LDAP_AUTH_SASL ) { - Debug( LDAP_DEBUG_TRACE, "do_sasl_bind: dn (%s) mech %s\n", + Debug( LDAP_DEBUG_TRACE, "do_bind: dn (%s) SASL mech %s\n", op->o_req_dn.bv_val, mech.bv_val, NULL ); } else { @@ -168,13 +177,9 @@ do_bind( (unsigned long) op->orb_method ); } - Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n", - op->o_log_prefix, op->o_req_dn.bv_val, - (unsigned long) op->orb_method, 0, 0 ); - if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) { - Debug( LDAP_DEBUG_ANY, "do_bind: unknown version=%ld\n", - (unsigned long) version, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_bind: unknown version=%ld\n", + op->o_log_prefix, (unsigned long) version, 0 ); send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "requested protocol version not supported" ); goto cleanup; @@ -194,7 +199,7 @@ do_bind( op->o_conn->c_protocol = version; ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); - op->orb_tmp_mech = mech; + op->orb_mech = mech; op->o_bd = frontendDB; rs->sr_err = frontendDB->be_bind( op, rs ); @@ -242,7 +247,7 @@ fe_op_bind( Operation *op, SlapReply *rs ) goto cleanup; } - if( BER_BVISNULL( &op->orb_tmp_mech ) || BER_BVISEMPTY( &op->orb_tmp_mech ) ) { + if( BER_BVISNULL( &op->orb_mech ) || BER_BVISEMPTY( &op->orb_mech ) ) { Debug( LDAP_DEBUG_ANY, "do_bind: no sasl mechanism provided\n", 0, 0, 0 ); @@ -252,19 +257,19 @@ fe_op_bind( Operation *op, SlapReply *rs ) } /* check restrictions */ - if( backend_check_restrictions( op, rs, &op->orb_tmp_mech ) != LDAP_SUCCESS ) { + if( backend_check_restrictions( op, rs, &op->orb_mech ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if ( op->o_conn->c_sasl_bind_in_progress ) { - if( !bvmatch( &op->o_conn->c_sasl_bind_mech, &op->orb_tmp_mech ) ) { + if( !bvmatch( &op->o_conn->c_sasl_bind_mech, &op->orb_mech ) ) { /* mechanism changed between bind steps */ slap_sasl_reset(op->o_conn); } } else { - ber_dupbv(&op->o_conn->c_sasl_bind_mech, &op->orb_tmp_mech); + ber_dupbv(&op->o_conn->c_sasl_bind_mech, &op->orb_mech); } /* Set the bindop for the benefit of in-directory SASL lookups */ @@ -291,7 +296,7 @@ fe_op_bind( Operation *op, SlapReply *rs ) } if ( op->orb_method == LDAP_AUTH_SIMPLE ) { - BER_BVSTR( &op->orb_tmp_mech, "SIMPLE" ); + BER_BVSTR( &op->orb_mech, "SIMPLE" ); /* accept "anonymous" binds */ if ( BER_BVISEMPTY( &op->orb_cred ) || BER_BVISEMPTY( &op->o_req_ndn ) ) { rs->sr_err = LDAP_SUCCESS; @@ -316,7 +321,7 @@ fe_op_bind( Operation *op, SlapReply *rs ) rs->sr_text = "anonymous bind disallowed"; } else { - backend_check_restrictions( op, rs, &op->orb_tmp_mech ); + backend_check_restrictions( op, rs, &op->orb_mech ); } /* @@ -357,7 +362,7 @@ fe_op_bind( Operation *op, SlapReply *rs ) * if we don't hold it. */ - if ( (op->o_bd = select_backend( &op->o_req_ndn, 0, 0 )) == NULL ) { + if ( (op->o_bd = select_backend( &op->o_req_ndn, 0 )) == NULL ) { /* don't return referral for bind requests */ /* noSuchObject is not allowed to be returned by bind */ rs->sr_err = LDAP_INVALID_CREDENTIALS; @@ -423,7 +428,7 @@ fe_op_bind_success( Operation *op, SlapReply *rs ) Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" mech=%s ssf=0\n", op->o_log_prefix, - op->o_conn->c_dn.bv_val, op->orb_tmp_mech.bv_val, 0, 0 ); + op->o_conn->c_dn.bv_val, op->orb_mech.bv_val, 0, 0 ); Debug( LDAP_DEBUG_TRACE, "do_bind: v%d bind: \"%s\" to \"%s\"\n", diff --git a/servers/slapd/cancel.c b/servers/slapd/cancel.c index 08115f45ed..dd4c79730c 100644 --- a/servers/slapd/cancel.c +++ b/servers/slapd/cancel.c @@ -56,18 +56,18 @@ int cancel_extop( Operation *op, SlapReply *rs ) (void) ber_free( ber, 1 ); + Statslog( LDAP_DEBUG_STATS, "%s CANCEL msg=%d\n", + op->o_log_prefix, opid, 0, 0, 0 ); + if ( opid < 0 ) { rs->sr_text = "message ID invalid"; return LDAP_PROTOCOL_ERROR; } - Statslog( LDAP_DEBUG_STATS, "%s CANCEL msg=%d\n", - op->o_log_prefix, opid, 0, 0, 0 ); - ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) { if ( o->o_msgid == opid ) { - LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops, o, slap_op, o_next ); + LDAP_STAILQ_REMOVE( &op->o_conn->c_pending_ops, o, Operation, o_next ); LDAP_STAILQ_NEXT(o, o_next) = NULL; op->o_conn->c_n_ops_pending--; slap_op_free( o ); diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 230602895a..900f585fa4 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -44,15 +44,10 @@ do_compare( struct berval dn = BER_BVNULL; struct berval desc = BER_BVNULL; struct berval value = BER_BVNULL; -#ifdef LDAP_COMP_MATCH - AttributeAssertion ava = { NULL, BER_BVNULL, NULL }; -#else - AttributeAssertion ava = { NULL, BER_BVNULL }; -#endif + AttributeAssertion ava = { 0 }; - ava.aa_desc = NULL; - - Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_compare\n", + op->o_log_prefix, 0, 0 ); /* * Parse the compare request. It looks like this: * @@ -66,37 +61,46 @@ do_compare( */ if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_compare: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } if ( ber_scanf( op->o_ber, "{mm}", &desc, &value ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_compare: get ava failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_compare: get ava failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } if ( ber_scanf( op->o_ber, /*{*/ "}" ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_compare: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_compare: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); goto cleanup; } rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "do_compare: invalid dn (%s)\n", dn.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_compare: invalid dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } + Statslog( LDAP_DEBUG_STATS, + "%s CMP dn=\"%s\" attr=\"%s\"\n", + op->o_log_prefix, op->o_req_dn.bv_val, + desc.bv_val, 0, 0 ); + rs->sr_err = slap_bv2ad( &desc, &ava.aa_desc, &rs->sr_text ); if( rs->sr_err != LDAP_SUCCESS ) { rs->sr_err = slap_bv2undef_ad( &desc, &ava.aa_desc, @@ -119,6 +123,11 @@ do_compare( op->orc_ava = &ava; + Debug( LDAP_DEBUG_ARGS, + "do_compare: dn (%s) attr (%s) value (%s)\n", + op->o_req_dn.bv_val, + ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); + op->o_bd = frontendDB; rs->sr_err = frontendDB->be_compare( op, rs ); @@ -136,21 +145,10 @@ int fe_op_compare( Operation *op, SlapReply *rs ) { Entry *entry = NULL; - int manageDSAit; - AttributeAssertion ava = *op->orc_ava; + AttributeAssertion *ava = op->orc_ava; BackendDB *bd = op->o_bd; if( strcasecmp( op->o_req_ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) { - Debug( LDAP_DEBUG_ARGS, - "do_compare: dn (%s) attr (%s) value (%s)\n", - op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); - - Statslog( LDAP_DEBUG_STATS, - "%s CMP dn=\"%s\" attr=\"%s\"\n", - op->o_log_prefix, op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, 0, 0 ); - if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; @@ -163,15 +161,6 @@ fe_op_compare( Operation *op, SlapReply *rs ) } } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { - Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", - op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); - - Statslog( LDAP_DEBUG_STATS, - "%s CMP dn=\"%s\" attr=\"%s\"\n", - op->o_log_prefix, op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, 0, 0 ); - if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rs->sr_err = 0; @@ -187,7 +176,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) } if( entry ) { - rs->sr_err = compare_entry( op, entry, &ava ); + rs->sr_err = compare_entry( op, entry, ava ); entry_free( entry ); send_ldap_result( op, rs ); @@ -201,14 +190,12 @@ fe_op_compare( Operation *op, SlapReply *rs ) goto cleanup; } - manageDSAit = get_manageDSAit( op ); - /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd == NULL ) { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); @@ -234,31 +221,21 @@ fe_op_compare( Operation *op, SlapReply *rs ) goto cleanup; } - Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n", - op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val ); - - Statslog( LDAP_DEBUG_STATS, "%s CMP dn=\"%s\" attr=\"%s\"\n", - op->o_log_prefix, op->o_req_dn.bv_val, - ava.aa_desc->ad_cname.bv_val, 0, 0 ); - - op->orc_ava = &ava; - if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) { /* don't use shadow copy */ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "copy not used" ); - } else if ( ava.aa_desc == slap_schema.si_ad_entryDN ) { + } else if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "entryDN compare not supported" ); - } else if ( ava.aa_desc == slap_schema.si_ad_subschemaSubentry ) { + } else if ( ava->aa_desc == slap_schema.si_ad_subschemaSubentry ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "subschemaSubentry compare not supported" ); #ifndef SLAP_COMPARE_IN_FRONTEND - } else if ( ava.aa_desc == slap_schema.si_ad_hasSubordinates + } else if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates && op->o_bd->be_has_subordinates ) { int rc, hasSubordinates = LDAP_SUCCESS; @@ -266,7 +243,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry ); if ( rc == 0 && entry ) { if ( ! access_allowed( op, entry, - ava.aa_desc, &ava.aa_value, ACL_COMPARE, NULL ) ) + ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) ) { rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; @@ -280,7 +257,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) if ( rc == 0 ) { int asserted; - asserted = bvmatch( &ava.aa_value, &slap_true_bv ) + asserted = bvmatch( &ava->aa_value, &slap_true_bv ) ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; if ( hasSubordinates == asserted ) { rs->sr_err = LDAP_COMPARE_TRUE; @@ -329,7 +306,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) int rc = LDAP_OTHER; rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, - ava.aa_desc, &vals, ACL_COMPARE ); + ava->aa_desc, &vals, ACL_COMPARE ); switch ( rs->sr_err ) { default: /* return error only if "disclose" @@ -347,7 +324,7 @@ fe_op_compare( Operation *op, SlapReply *rs ) if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - vals, &ava.aa_value, op->o_tmpmemctx ) == 0 ) + vals, &ava->aa_value, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; break; diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 54dcf2d571..d6655a78a0 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -41,7 +41,7 @@ #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) #endif -#if HAVE_UNISTD_H +#ifdef HAVE_UNISTD_H #include #endif @@ -53,10 +53,6 @@ #include "lutil_ldap.h" #include "config.h" -#ifdef HAVE_TLS -#include -#endif - #define ARGS_STEP 512 /* @@ -145,54 +141,54 @@ int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) { c->argv[1] = ""; } if(Conf->min_args && (c->argc < Conf->min_args)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> missing <%s> argument", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> missing <%s> argument", c->argv[0], Conf->what ); - Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->msg, 0 ); + Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg, 0 ); return(ARG_BAD_CONF); } if(Conf->max_args && (c->argc > Conf->max_args)) { char *ignored = " ignored"; - snprintf( c->msg, sizeof( c->msg ), "<%s> extra cruft after <%s>", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> extra cruft after <%s>", c->argv[0], Conf->what ); ignored = ""; Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s.\n", - c->log, c->msg, ignored ); + c->log, c->cr_msg, ignored ); return(ARG_BAD_CONF); } if((arg_syn & ARG_DB) && !c->be) { - snprintf( c->msg, sizeof( c->msg ), "<%s> only allowed within database declaration", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> only allowed within database declaration", c->argv[0] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } if((arg_syn & ARG_PRE_BI) && c->bi) { - snprintf( c->msg, sizeof( c->msg ), "<%s> must occur before any backend %sdeclaration", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any backend %sdeclaration", c->argv[0], (arg_syn & ARG_PRE_DB) ? "or database " : "" ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(ARG_BAD_CONF); } if((arg_syn & ARG_PRE_DB) && c->be && c->be != frontendDB) { - snprintf( c->msg, sizeof( c->msg ), "<%s> must occur before any database declaration", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any database declaration", c->argv[0] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } if((arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) { - snprintf( c->msg, sizeof( c->msg ), "<%s> old format not supported", c->argv[0] ); + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> old format not supported", c->argv[0] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } if(arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET)) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid config_table, arg_item is NULL", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid config_table, arg_item is NULL", c->argv[0] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } c->type = arg_user; @@ -208,9 +204,9 @@ int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) { ber_str2bv( c->argv[1], 0, 0, &bv ); rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid DN %d (%s)", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid DN %d (%s)", c->argv[0], rc, ldap_err2string( rc )); - Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->msg, 0); + Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } if ( check_only ) { @@ -223,32 +219,32 @@ int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) { switch(arg_type) { case ARG_INT: if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse \"%s\" as int", c->argv[0], c->argv[1] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } break; case ARG_LONG: if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse \"%s\" as long", c->argv[0], c->argv[1] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } break; case ARG_BER_LEN_T: { unsigned long l; if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse \"%s\" as ber_len_t", c->argv[0], c->argv[1] ); Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } barg = (ber_len_t)l; @@ -267,10 +263,10 @@ int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) { { iarg = 0; } else { - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(ARG_BAD_CONF); } break; @@ -278,10 +274,10 @@ int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) { j = (arg_type & ARG_NONZERO) ? 1 : 0; if(iarg < j && larg < j && barg < j ) { larg = larg ? larg : (barg ? barg : iarg); - snprintf( c->msg, sizeof( c->msg ), "<%s> invalid value", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return(ARG_BAD_CONF); } switch(arg_type) { @@ -301,33 +297,32 @@ int config_set_vals(ConfigTable *Conf, ConfigArgs *c) { arg_type = Conf->arg_type; if(arg_type & ARG_MAGIC) { if(!c->be) c->be = frontendDB; - c->msg[0] = '\0'; + c->cr_msg[0] = '\0'; rc = (*((ConfigDriver*)Conf->arg_item))(c); #if 0 if(c->be == frontendDB) c->be = NULL; #endif if(rc) { - if ( !c->msg[0] ) { - snprintf( c->msg, sizeof( c->msg ), "<%s> handler exited with %d", + if ( !c->cr_msg[0] ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> handler exited with %d", c->argv[0], rc ); Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); } return(ARG_BAD_CONF); } return(0); } if(arg_type & ARG_OFFSET) { - if (c->be && (!overlay_is_over(c->be) || - ((slap_overinfo *)c->be->bd_info)->oi_orig == c->bi)) + if (c->be && c->table == Cft_Database) ptr = c->be->be_private; else if (c->bi) ptr = c->bi->bi_private; else { - snprintf( c->msg, sizeof( c->msg ), "<%s> offset is missing base pointer", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer", c->argv[0] ); Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n", - c->log, c->msg, 0); + c->log, c->cr_msg, 0); return(ARG_BAD_CONF); } ptr = (void *)((char *)ptr + (long)Conf->arg_item); @@ -410,8 +405,7 @@ config_get_vals(ConfigTable *cf, ConfigArgs *c) if ( rc ) return rc; } else { if ( cf->arg_type & ARG_OFFSET ) { - if (c->be && (!overlay_is_over(c->be) || - ((slap_overinfo *)c->be->bd_info)->oi_orig == c->bi)) + if (c->be && c->table == Cft_Database) ptr = c->be->be_private; else if ( c->bi ) ptr = c->bi->bi_private; @@ -728,6 +722,7 @@ read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft) ct = config_find_keyword( cft, c ); if ( ct ) { + c->table = Cft_Global; rc = config_add_vals( ct, c ); if ( !rc ) continue; @@ -748,6 +743,7 @@ read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft) if ( c->bi->bi_cf_ocs ) { ct = config_find_keyword( c->bi->bi_cf_ocs->co_table, c ); if ( ct ) { + c->table = c->bi->bi_cf_ocs->co_type; rc = config_add_vals( ct, c ); } } @@ -772,6 +768,7 @@ read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft) if ( c->be->be_cf_ocs ) { ct = config_find_keyword( c->be->be_cf_ocs->co_table, c ); if ( ct ) { + c->table = c->be->be_cf_ocs->co_type; rc = config_add_vals( ct, c ); } } @@ -1040,7 +1037,7 @@ static slap_cf_aux_table bindkey[] = { { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL }, { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL }, { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL }, - { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 0, (slap_verbmasks *)authzNormalize }, + { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 1, NULL }, { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, (slap_verbmasks *)authzNormalize }, #ifdef HAVE_TLS { BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 'i', 0, tlskey }, @@ -1350,12 +1347,6 @@ void bindconf_free( slap_bindconf *bc ) { BER_BVZERO( &bc->sb_authzId ); } #ifdef HAVE_TLS -#if 0 - if ( bc->sb_tls_ctx ) { - SSL_CTX_free( bc->sb_tls_ctx ); - bc->sb_tls_ctx = NULL; - } -#endif if ( bc->sb_tls_cert ) { ch_free( bc->sb_tls_cert ); bc->sb_tls_cert = NULL; @@ -1482,7 +1473,7 @@ int bindconf_tls_set( slap_bindconf *bc, LDAP *ld ) int opt = 0; if ( bc->sb_tls_ctx ) { - SSL_CTX_free( bc->sb_tls_ctx ); + ldap_pvt_tls_ctx_free( bc->sb_tls_ctx ); bc->sb_tls_ctx = NULL; } rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); @@ -1593,6 +1584,10 @@ slap_client_connect( LDAP **ldp, slap_bindconf *sb ) sb->sb_authcId.bv_val, sb->sb_cred.bv_val, sb->sb_authzId.bv_val ); + if ( defaults == NULL ) { + rc = LDAP_OTHER; + goto done; + } rc = ldap_sasl_interactive_bind_s( ld, sb->sb_binddn.bv_val, @@ -1914,7 +1909,9 @@ int config_generic_wrapper( Backend *be, const char *fname, int lineno, rc = SLAP_CONF_UNKNOWN; ct = config_find_keyword( be->be_cf_ocs->co_table, &c ); - if ( ct ) + if ( ct ) { + c.table = be->be_cf_ocs->co_type; rc = config_add_vals( ct, &c ); + } return rc; } diff --git a/servers/slapd/config.h b/servers/slapd/config.h index eac44942e9..be5e2925a8 100644 --- a/servers/slapd/config.h +++ b/servers/slapd/config.h @@ -17,6 +17,8 @@ #ifndef CONFIG_H #define CONFIG_H +#include + typedef struct ConfigTable { char *name; char *what; @@ -105,6 +107,11 @@ typedef struct ConfigOCs { typedef int (ConfigDriver)(struct config_args_s *c); +typedef struct config_reply_s { + int err; + char msg[SLAP_TEXT_BUFLEN]; +} ConfigReply; + typedef struct config_args_s { int argc; char **argv; @@ -114,7 +121,8 @@ typedef struct config_args_s { const char *fname; int lineno; char log[MAXPATHLEN + STRLENOF(": line 18446744073709551615") + 1]; - char msg[SLAP_TEXT_BUFLEN]; +#define cr_msg reply.msg + ConfigReply reply; int depth; int valx; /* multi-valued value index */ /* parsed first val for simple cases */ @@ -142,6 +150,7 @@ typedef struct config_args_s { Entry *ca_entry; /* entry being modified */ void *private; /* anything */ ConfigDriver *cleanup; + ConfigType table; /* which config table did we come from */ } ConfigArgs; /* If lineno is zero, we have an actual LDAP Add request from a client. diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 062734c449..9ec67f503a 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -359,14 +359,15 @@ static void connection_return( Connection *c ) ldap_pvt_thread_mutex_unlock( &c->c_mutex ); } -long connection_init( +Connection * connection_init( ber_socket_t s, Listener *listener, const char* dnsname, const char* peername, int flags, slap_ssf_t ssf, - struct berval *authid ) + struct berval *authid + LDAP_PF_LOCAL_SENDMSG_ARG(struct berval *peerbv)) { unsigned long id; Connection *c; @@ -379,13 +380,13 @@ long connection_init( assert( peername != NULL ); #ifndef HAVE_TLS - assert( flags != CONN_IS_TLS ); + assert( !( flags & CONN_IS_TLS )); #endif if( s == AC_SOCKET_INVALID ) { Debug( LDAP_DEBUG_ANY, "connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 ); - return -1; + return NULL; } assert( s >= 0 ); @@ -442,7 +443,7 @@ long connection_init( Debug( LDAP_DEBUG_ANY, "connection_init(%d): connection table full " "(%d/%d)\n", s, i, dtblsize); - return -1; + return NULL; } } #endif @@ -525,14 +526,15 @@ long connection_init( c->c_listener = listener; - if ( flags == CONN_IS_CLIENT ) { + if ( flags & CONN_IS_CLIENT ) { + c->c_connid = 0; c->c_conn_state = SLAP_C_CLIENT; c->c_struct_state = SLAP_C_USED; c->c_close_reason = "?"; /* should never be needed */ ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - return 0; + return c; } ber_str2bv( dnsname, 0, 1, &c->c_peer_domain ); @@ -559,7 +561,7 @@ long connection_init( #ifdef LDAP_CONNECTIONLESS c->c_is_udp = 0; - if( flags == CONN_IS_UDP ) { + if( flags & CONN_IS_UDP ) { c->c_is_udp = 1; #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, @@ -570,7 +572,21 @@ long connection_init( ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead, LBER_SBIOD_LEVEL_PROVIDER, NULL ); } else +#endif /* LDAP_CONNECTIONLESS */ +#ifdef LDAP_PF_LOCAL + if ( flags & CONN_IS_IPC ) { +#ifdef LDAP_DEBUG + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, + LBER_SBIOD_LEVEL_PROVIDER, (void*)"ipc_" ); #endif + ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_fd, + LBER_SBIOD_LEVEL_PROVIDER, (void *)&s ); +#ifdef LDAP_PF_LOCAL_SENDMSG + if ( !BER_BVISEMPTY( peerbv )) + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_UNGET_BUF, peerbv ); +#endif + } else +#endif /* LDAP_PF_LOCAL */ { #ifdef LDAP_DEBUG ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug, @@ -605,7 +621,7 @@ long connection_init( c->c_tls_ssf = 0; #ifdef HAVE_TLS - if ( flags == CONN_IS_TLS ) { + if ( flags & CONN_IS_TLS ) { c->c_is_tls = 1; c->c_needs_tls_accept = 1; } else { @@ -622,7 +638,7 @@ long connection_init( backend_connection_init(c); - return id; + return c; } void connection2anonymous( Connection *c ) @@ -1022,12 +1038,12 @@ void connection_done( Connection *c ) static BI_op_func *opfun[] = { do_bind, do_unbind, + do_search, + do_compare, + do_modify, + do_modrdn, do_add, do_delete, - do_modrdn, - do_modify, - do_compare, - do_search, do_abandon, do_extended, NULL @@ -1157,7 +1173,7 @@ operations_error: ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx_null ); - LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); + LDAP_STAILQ_REMOVE( &conn->c_ops, op, Operation, o_next); LDAP_STAILQ_NEXT(op, o_next) = NULL; slap_op_free( op ); conn->c_n_ops_executing--; @@ -1184,20 +1200,18 @@ int connection_client_setup( ldap_pvt_thread_start_t *func, void *arg ) { - int rc; Connection *c; - rc = connection_init( s, (Listener *)&dummy_list, "", "", - CONN_IS_CLIENT, 0, NULL ); - if ( rc < 0 ) return -1; + c = connection_init( s, (Listener *)&dummy_list, "", "", + CONN_IS_CLIENT, 0, NULL + LDAP_PF_LOCAL_SENDMSG_ARG(NULL)); + if ( !c ) return -1; - c = connection_get( s ); c->c_clientfunc = func; c->c_clientarg = arg; slapd_add_internal( s, 0 ); slapd_set_read( s, 1 ); - connection_return( c ); return 0; } @@ -1438,7 +1452,7 @@ int connection_read(ber_socket_t s) } #ifdef DATA_READY_LOOP while( !rc && ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_DATA_READY, NULL )); -#elif CONNECTION_INPUT_LOOP +#elif defined CONNECTION_INPUT_LOOP while(!rc); #else while(0); @@ -1801,13 +1815,14 @@ static int connection_bind_cb( Operation *op, SlapReply *rs ) /* log authorization identity */ Statslog( LDAP_DEBUG_STATS, - "%s BIND dn=\"%s\" mech=%s ssf=%d\n", + "%s BIND dn=\"%s\" mech=%s sasl_ssf=%d ssf=%d\n", op->o_log_prefix, BER_BVISNULL( &op->o_conn->c_dn ) ? "" : op->o_conn->c_dn.bv_val, - op->o_conn->c_authmech.bv_val, op->orb_ssf, 0 ); + op->o_conn->c_authmech.bv_val, + op->orb_ssf, op->o_conn->c_ssf ); Debug( LDAP_DEBUG_TRACE, - "do_bind: SASL/%s bind: dn=\"%s\" ssf=%d\n", + "do_bind: SASL/%s bind: dn=\"%s\" sasl_ssf=%d\n", op->o_conn->c_authmech.bv_val, BER_BVISNULL( &op->o_conn->c_dn ) ? "" : op->o_conn->c_dn.bv_val, op->orb_ssf ); @@ -1979,19 +1994,21 @@ connection_fake_destroy( void connection_fake_init( Connection *conn, - Operation *op, + OperationBuffer *opbuf, void *ctx ) { - connection_fake_init2( conn, op, ctx, 1 ); + connection_fake_init2( conn, opbuf, ctx, 1 ); } void connection_fake_init2( Connection *conn, - Operation *op, + OperationBuffer *opbuf, void *ctx, int newmem ) { + Operation *op = (Operation *) opbuf; + conn->c_connid = -1; conn->c_send_ldap_result = slap_send_ldap_result; conn->c_send_search_entry = slap_send_search_entry; @@ -2000,9 +2017,10 @@ connection_fake_init2( conn->c_peer_domain = slap_empty_bv; conn->c_peer_name = slap_empty_bv; - memset(op, 0, OPERATION_BUFFER_SIZE); - op->o_hdr = (Opheader *)(op+1); - op->o_controls = (void **)(op->o_hdr+1); + memset( opbuf, 0, sizeof( *opbuf )); + op->o_hdr = &opbuf->ob_hdr; + op->o_controls = opbuf->ob_controls; + /* set memory context */ op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, newmem ); @@ -2016,10 +2034,11 @@ connection_fake_init2( #ifdef LDAP_SLAPI if ( slapi_plugins_used ) { - conn_fake_extblock *eb = NULL; + conn_fake_extblock *eb; + void *ebx = NULL; /* Use thread keys to make sure these eventually get cleaned up */ - if ( ldap_pvt_thread_pool_getkey( ctx, connection_fake_init, &eb, + if ( ldap_pvt_thread_pool_getkey( ctx, connection_fake_init, &ebx, NULL )) { eb = ch_malloc( sizeof( *eb )); slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, conn ); @@ -2029,6 +2048,7 @@ connection_fake_init2( ldap_pvt_thread_pool_setkey( ctx, connection_fake_init, eb, connection_fake_destroy ); } else { + eb = ebx; conn->c_extensions = eb->eb_conn; op->o_hdr->oh_extensions = eb->eb_op; } diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index f9e9b9b076..ed887e5f1a 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -21,6 +21,8 @@ #include #include "slap.h" +#include "ldif.h" +#include "lutil.h" #include "../../libraries/liblber/lber-int.h" @@ -35,7 +37,7 @@ static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead; static SLAP_CTRL_PARSE_FN parseProxyAuthz; static SLAP_CTRL_PARSE_FN parseRelax; static SLAP_CTRL_PARSE_FN parseSearchOptions; -#ifdef SLAP_SORTEDRESULTS +#ifdef SLAP_CONTROL_X_SORTEDRESULTS static SLAP_CTRL_PARSE_FN parseSortedResults; #endif static SLAP_CTRL_PARSE_FN parseSubentries; @@ -43,6 +45,9 @@ static SLAP_CTRL_PARSE_FN parseSubentries; static SLAP_CTRL_PARSE_FN parseTreeDelete; #endif static SLAP_CTRL_PARSE_FN parseValuesReturnFilter; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +static SLAP_CTRL_PARSE_FN parseSessionTracking; +#endif #undef sc_mask /* avoid conflict with Irix 6.5 */ @@ -103,6 +108,15 @@ static char *manageDSAit_extops[] = { NULL }; +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +static char *session_tracking_extops[] = { + LDAP_EXOP_MODIFY_PASSWD, + LDAP_EXOP_WHO_AM_I, + LDAP_EXOP_REFRESH, + NULL +}; +#endif + static struct slap_control control_defs[] = { { LDAP_CONTROL_ASSERT, (int)offsetof(struct slap_control_ids, sc_assert), @@ -130,7 +144,7 @@ static struct slap_control control_defs[] = { SLAP_CTRL_SEARCH, NULL, NULL, parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) }, -#ifdef SLAP_SORTEDRESULTS +#ifdef SLAP_CONTROL_X_SORTEDRESULTS { LDAP_CONTROL_SORTREQUEST, (int)offsetof(struct slap_control_ids, sc_sortedResults), SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE, @@ -196,6 +210,13 @@ static struct slap_control control_defs[] = { SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS, proxy_authz_extops, NULL, parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + { LDAP_CONTROL_X_SESSION_TRACKING, + (int)offsetof(struct slap_control_ids, sc_sessionTracking), + SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, + session_tracking_extops, NULL, + parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) }, +#endif { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) } }; @@ -849,8 +870,8 @@ static int parseDontUseCopy ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "dontUseCopy control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "dontUseCopy control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -873,8 +894,8 @@ static int parseRelax ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "relax control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "relax control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -895,8 +916,8 @@ static int parseManageDSAit ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "manageDSAit control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "manageDSAit control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -920,6 +941,11 @@ static int parseProxyAuthz ( return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "proxy authorization control value absent"; + return LDAP_PROTOCOL_ERROR; + } + if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON ) && BER_BVISEMPTY( &op->o_ndn ) ) { @@ -937,7 +963,7 @@ static int parseProxyAuthz ( ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous", 0 ); - if ( ctrl->ldctl_value.bv_len == 0 ) { + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { Debug( LDAP_DEBUG_TRACE, "parseProxyAuthz: conn=%lu anonymous\n", op->o_connid, 0, 0 ); @@ -1007,7 +1033,7 @@ static int parseNoOp ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { + if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { rs->sr_text = "noop control value not empty"; return LDAP_PROTOCOL_ERROR; } @@ -1036,8 +1062,13 @@ static int parsePagedResults ( return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "paged results control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { - rs->sr_text = "paged results control value is empty (or absent)"; + rs->sr_text = "paged results control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1099,7 +1130,7 @@ done:; return rc; } -#ifdef SLAP_SORTEDRESULTS +#ifdef SLAP_CONTROL_X_SORTEDRESULTS static int parseSortedResults ( Operation *op, SlapReply *rs, @@ -1112,8 +1143,13 @@ static int parseSortedResults ( return LDAP_PROTOCOL_ERROR; } + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "sorted results control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { - rs->sr_text = "sorted results control value is empty (or absent)"; + rs->sr_text = "sorted results control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1140,8 +1176,13 @@ static int parseAssert ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "assert control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "assert control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "assert control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1198,8 +1239,13 @@ static int parsePreRead ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "preread control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "preread control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "preread control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1266,8 +1312,13 @@ static int parsePostRead ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "postread control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "postread control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "postread control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1351,8 +1402,13 @@ static int parseValuesReturnFilter ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "valuesReturnFilter control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "valuesReturnFilter control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "valuesReturnFilter control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1435,8 +1491,8 @@ static int parsePermissiveModify ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "permissiveModify control value not empty"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "permissiveModify control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -1457,7 +1513,7 @@ static int parseDomainScope ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { + if ( BER_BVISNULL( &ctrl->ldctl_value )) { rs->sr_text = "domainScope control value not empty"; return LDAP_PROTOCOL_ERROR; } @@ -1480,8 +1536,8 @@ static int parseTreeDelete ( return LDAP_PROTOCOL_ERROR; } - if ( ctrl->ldctl_value.bv_len ) { - rs->sr_text = "treeDelete control value not empty"; + if ( !BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "treeDelete control value not absent"; return LDAP_PROTOCOL_ERROR; } @@ -1502,8 +1558,13 @@ static int parseSearchOptions ( ber_int_t search_flags; ber_tag_t tag; - if ( ctrl->ldctl_value.bv_len == 0 ) { - rs->sr_text = "searchOptions control value is empty (or absent)"; + if ( BER_BVISNULL( &ctrl->ldctl_value )) { + rs->sr_text = "searchOptions control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value )) { + rs->sr_text = "searchOptions control value is empty"; return LDAP_PROTOCOL_ERROR; } @@ -1545,3 +1606,299 @@ static int parseSearchOptions ( return LDAP_SUCCESS; } +#ifdef SLAP_CONTROL_X_SESSION_TRACKING +struct berval session_tracking_formats[] = { + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID ), + BER_BVC( "RADIUS-Acct-Session-Id" ), + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID ), + BER_BVC( "RADIUS-Acct-Multi-Session-Id" ), + BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ), + BER_BVC( "USERNAME" ), + + BER_BVNULL +}; + +static int parseSessionTracking( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) +{ + BerElement *ber; + ber_tag_t tag; + ber_len_t len; + int i, rc; + + struct berval sessionSourceIp = BER_BVNULL, + sessionSourceName = BER_BVNULL, + formatOID = BER_BVNULL, + sessionTrackingIdentifier = BER_BVNULL; + + size_t st_len, st_pos; + + if ( ctrl->ldctl_iscritical ) { + rs->sr_text = "sessionTracking criticality is TRUE"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + rs->sr_text = "sessionTracking control value is absent"; + return LDAP_PROTOCOL_ERROR; + } + + if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { + rs->sr_text = "sessionTracking control value is empty"; + return LDAP_PROTOCOL_ERROR; + } + + ber = ber_init( &ctrl->ldctl_value ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_SEQUENCE ) { + tag = LBER_ERROR; + goto error; + } + + /* sessionSourceIp */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else if ( len > 128 ) { + rs->sr_text = "sessionTracking.sessionSourceIp too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &sessionSourceIp ); + } + + if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) { + BER_BVZERO( &sessionSourceIp ); + } + + /* sessionSourceName */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else if ( len > 65536 ) { + rs->sr_text = "sessionTracking.sessionSourceName too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &sessionSourceName ); + } + + if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) { + BER_BVZERO( &sessionSourceName ); + } + + /* formatOID */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + rs->sr_text = "sessionTracking.formatOID empty"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else if ( len > 1024 ) { + rs->sr_text = "sessionTracking.formatOID too long"; + rs->sr_err = LDAP_PROTOCOL_ERROR; + goto error; + + } else { + tag = ber_scanf( ber, "m", &formatOID ); + } + + rc = numericoidValidate( NULL, &formatOID ); + if ( rc != LDAP_SUCCESS ) { + rs->sr_text = "sessionTracking.formatOID invalid"; + goto error; + } + + for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 ) + { + if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) { + formatOID = session_tracking_formats[ i + 1 ]; + break; + } + } + + /* sessionTrackingIdentifier */ + tag = ber_peek_tag( ber, &len ); + if ( tag == LBER_DEFAULT ) { + tag = LBER_ERROR; + goto error; + } + + if ( len == 0 ) { + tag = ber_skip_tag( ber, &len ); + + } else { + /* note: should not be more than 65536... */ + tag = ber_scanf( ber, "m", &sessionTrackingIdentifier ); + if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) { + /* we want the OID printed, at least */ + BER_BVSTR( &sessionTrackingIdentifier, "" ); + } + } + + /* closure */ + tag = ber_skip_tag( ber, &len ); + if ( tag != LBER_DEFAULT || len != 0 ) { + tag = LBER_ERROR; + goto error; + } + tag = 0; + + st_len = 0; + if ( !BER_BVISNULL( &sessionSourceIp ) ) { + st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len; + } + if ( !BER_BVISNULL( &sessionSourceName ) ) { + if ( st_len ) st_len++; + st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len; + } + if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) { + if ( st_len ) st_len++; + st_len += formatOID.bv_len + STRLENOF( "=" ) + + sessionTrackingIdentifier.bv_len; + } + + if ( st_len == 0 ) { + goto error; + } + + st_len += STRLENOF( " []" ); + st_pos = strlen( op->o_log_prefix ); + + if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) { + char *ptr = &op->o_log_prefix[ st_pos ]; + + ptr = lutil_strcopy( ptr, " [" /*]*/ ); + + st_len = 0; + if ( !BER_BVISNULL( &sessionSourceIp ) ) { + ptr = lutil_strcopy( ptr, "IP=" ); + ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val ); + st_len++; + } + + if ( !BER_BVISNULL( &sessionSourceName ) ) { + if ( st_len ) *ptr++ = ' '; + ptr = lutil_strcopy( ptr, "NAME=" ); + ptr = lutil_strcopy( ptr, sessionSourceName.bv_val ); + st_len++; + } + + if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) { + if ( st_len ) *ptr++ = ' '; + ptr = lutil_strcopy( ptr, formatOID.bv_val ); + *ptr++ = '='; + ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val ); + } + + *ptr++ = /*[*/ ']'; + *ptr = '\0'; + } + +error:; + (void)ber_free( ber, 1 ); + + if ( tag == LBER_ERROR ) { + rs->sr_text = "sessionTracking control decoding error"; + return LDAP_PROTOCOL_ERROR; + } + + + return rs->sr_err; +} + +int +slap_ctrl_session_tracking_add( + Operation *op, + SlapReply *rs, + struct berval *ip, + struct berval *name, + struct berval *id, + LDAPControl *ctrl ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + static struct berval oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME ); + + assert( ctrl != NULL ); + + ber_init2( ber, NULL, LBER_USE_DER ); + + ber_printf( ber, "{OOOO}", ip, name, &oid, id ); + + if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) { + rs->sr_err = LDAP_OTHER; + goto done; + } + + ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING; + ctrl->ldctl_iscritical = 0; + + rs->sr_err = LDAP_SUCCESS; + +done:; + return rs->sr_err; +} + +int +slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl ) +{ + static struct berval bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN ); + struct berval ip = BER_BVNULL, + name = BER_BVNULL, + id = BER_BVNULL; + + if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) && + memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) + { + char *ptr; + + ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" ); + ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" ); + + ptr = ber_bvchr( &ip, ':' ); + if ( ptr ) { + ip.bv_len = ptr - ip.bv_val; + } + } + + if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) && + !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) ) + { + name = op->o_conn->c_peer_domain; + } + + if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) { + id = op->o_dn; + } + + return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl ); +} +#endif diff --git a/servers/slapd/cr.c b/servers/slapd/cr.c index 5e40ce202b..e18c0125af 100644 --- a/servers/slapd/cr.c +++ b/servers/slapd/cr.c @@ -30,7 +30,7 @@ struct cindexrec { }; static Avlnode *cr_index = NULL; -static LDAP_STAILQ_HEAD(CRList, slap_content_rule) cr_list +static LDAP_STAILQ_HEAD(CRList, ContentRule) cr_list = LDAP_STAILQ_HEAD_INITIALIZER(cr_list); static int diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 9f86d3d130..5949e543d7 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -50,14 +50,9 @@ #endif /* ! epoll && ! /dev/poll */ #ifdef HAVE_TCPD -# include int allow_severity = LOG_INFO; int deny_severity = LOG_NOTICE; - -# define SLAP_STRING_UNKNOWN STRING_UNKNOWN -#else /* ! TCP Wrappers */ -# define SLAP_STRING_UNKNOWN "unknown" -#endif /* ! TCP Wrappers */ +#endif /* TCP Wrappers */ #ifdef LDAP_PF_LOCAL # include @@ -227,7 +222,8 @@ static struct slap_daemon { (int *)(ptr) <= &slap_daemon.sd_index[dtblsize]) ? 0 : 1 ) # define SLAP_EPOLL_EV_PTRFD(ptr) (SLAP_EPOLL_EV_LISTENER(ptr) ? \ - ((Listener *)ptr)->sl_sd : (int *)(ptr) - slap_daemon.sd_index) + ((Listener *)ptr)->sl_sd : \ + (ber_socket_t) ((int *)(ptr) - slap_daemon.sd_index)) # define SLAP_SOCK_DEL(s) do { \ int fd, rc, index = SLAP_EPOLL_SOCK_IX((s)); \ @@ -1434,7 +1430,7 @@ slapd_daemon_init( const char *urls ) #ifdef HAVE_SYSCONF dtblsize = sysconf( _SC_OPEN_MAX ); -#elif HAVE_GETDTABLESIZE +#elif defined(HAVE_GETDTABLESIZE) dtblsize = getdtablesize(); #else /* ! HAVE_SYSCONF && ! HAVE_GETDTABLESIZE */ dtblsize = FD_SETSIZE; @@ -1571,8 +1567,8 @@ slap_listener( Sockaddr from; ber_socket_t s; - socklen_t len = sizeof(from); - long id; + ber_socklen_t len = sizeof(from); + Connection *c; slap_ssf_t ssf = 0; struct berval authid = BER_BVNULL; #ifdef SLAPD_RLOOKUPS @@ -1583,11 +1579,16 @@ slap_listener( char *peeraddr = NULL; #ifdef LDAP_PF_LOCAL char peername[MAXPATHLEN + sizeof("PATH=")]; +#ifdef LDAP_PF_LOCAL_SENDMSG + char peerbuf[8]; + struct berval peerbv = BER_BVNULL; +#endif #elif defined(LDAP_PF_INET6) char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")]; #else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */ char peername[sizeof("IP=255.255.255.255:65336")]; #endif /* LDAP_PF_LOCAL */ + int cflag; Debug( LDAP_DEBUG_TRACE, ">>> slap_listener(%s)\n", @@ -1700,9 +1701,12 @@ slap_listener( "daemon: listen=%ld, new connection on %ld\n", (long) sl->sl_sd, (long) s, 0 ); + cflag = 0; switch ( from.sa_addr.sa_family ) { # ifdef LDAP_PF_LOCAL case AF_LOCAL: + cflag |= CONN_IS_IPC; + /* FIXME: apparently accept doesn't fill * the sun_path sun_path member */ if ( from.sa_un_addr.sun_path[0] == '\0' ) { @@ -1717,7 +1721,11 @@ slap_listener( uid_t uid; gid_t gid; - if( getpeereid( s, &uid, &gid ) == 0 ) { +#ifdef LDAP_PF_LOCAL_SENDMSG + peerbv.bv_val = peerbuf; + peerbv.bv_len = sizeof( peerbuf ); +#endif + if( LUTIL_GETPEEREID( s, &uid, &gid, &peerbv ) == 0 ) { authid.bv_val = ch_malloc( STRLENOF( "gidNumber=4294967295+uidNumber=4294967295," "cn=peercred,cn=external,cn=auth" ) + 1 ); @@ -1809,20 +1817,18 @@ slap_listener( #endif /* HAVE_TCPD */ } - id = connection_init(s, sl, - dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN, - peername, #ifdef HAVE_TLS - sl->sl_is_tls ? CONN_IS_TLS : 0, -#else /* ! HAVE_TLS */ - 0, -#endif /* ! HAVE_TLS */ - ssf, - authid.bv_val ? &authid : NULL ); + if ( sl->sl_is_tls ) cflag |= CONN_IS_TLS; +#endif + c = connection_init(s, sl, + dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN, + peername, cflag, ssf, + authid.bv_val ? &authid : NULL + LDAP_PF_LOCAL_SENDMSG_ARG(&peerbv)); if( authid.bv_val ) ch_free(authid.bv_val); - if( id < 0 ) { + if( !c ) { Debug( LDAP_DEBUG_ANY, "daemon: connection_init(%ld, %s, %s) failed.\n", (long) s, peername, sl->sl_name.bv_val ); @@ -1832,7 +1838,7 @@ slap_listener( Statslog( LDAP_DEBUG_STATS, "conn=%ld fd=%ld ACCEPT from %s (%s)\n", - id, (long) s, peername, sl->sl_name.bv_val, + c->c_connid, (long) s, peername, sl->sl_name.bv_val, 0 ); return 0; @@ -1986,15 +1992,6 @@ slapd_daemon_task( } #endif /* HAVE_NT_SERVICE_MANAGER */ -#ifdef SLAP_SEM_LOAD_CONTROL - /* - * initialize count and lazyness of a semaphore - */ - (void) ldap_lazy_sem_init( - SLAP_MAX_WORKER_THREADS + 4 /* max workers + margin */, - 4 /* lazyness */ ); -#endif /* SLAP_SEM_LOAD_CONTROL */ - /* initialization complete. Here comes the loop. */ while ( !slapd_shutdown ) { @@ -2113,8 +2110,14 @@ slapd_daemon_task( ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); if ( rtask && cat.tv_sec ) { - time_t diff = difftime( cat.tv_sec, now ); - if ( diff == 0 ) diff = tdelta; + /* NOTE: diff __should__ always be >= 0, + * AFAI understand; however (ITS#4872), + * time_t might be unsigned in some systems, + * while difftime() returns a double */ + double diff = difftime( cat.tv_sec, now ); + if ( diff <= 0 ) { + diff = tdelta; + } if ( tvp == NULL || diff < tv.tv_sec ) { tv.tv_sec = diff; tv.tv_usec = 0; @@ -2510,16 +2513,17 @@ connectionless_init( void ) for ( l = 0; slap_listeners[l] != NULL; l++ ) { Listener *lr = slap_listeners[l]; - long id; + Connection *c; if ( !lr->sl_is_udp ) { continue; } - id = connection_init( lr->sl_sd, lr, "", "", - CONN_IS_UDP, (slap_ssf_t) 0, NULL ); + c = connection_init( lr->sl_sd, lr, "", "", + CONN_IS_UDP, (slap_ssf_t) 0, NULL + LDAP_PF_LOCAL_SENDMSG_ARG(NULL)); - if ( id < 0 ) { + if ( !c ) { Debug( LDAP_DEBUG_TRACE, "connectionless_init: failed on %s (%d)\n", lr->sl_url, lr->sl_sd, 0 ); @@ -2633,7 +2637,7 @@ slap_sig_shutdown( int sig ) * SIGBREAK is generated when a user logs out. */ -#if HAVE_NT_SERVICE_MANAGER && SIGBREAK +#if defined(HAVE_NT_SERVICE_MANAGER) && defined(SIGBREAK) if (is_NT_Service && sig == SIGBREAK) { /* empty */; } else diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index e31c51bbdb..eecc72445c 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -41,8 +41,8 @@ do_delete( { struct berval dn = BER_BVNULL; - Debug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 ); - + Debug( LDAP_DEBUG_TRACE, "%s do_delete\n", + op->o_log_prefix, 0, 0 ); /* * Parse the delete request. It looks like this: * @@ -50,43 +50,47 @@ do_delete( */ if ( ber_scanf( op->o_ber, "m", &dn ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_delete: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_delete: get_ctrls failed\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_delete: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); goto cleanup; } rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "do_delete: invalid dn (%s)\n", dn.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_delete: invalid dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } + Statslog( LDAP_DEBUG_STATS, "%s DEL dn=\"%s\"\n", + op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); + if( op->o_req_ndn.bv_len == 0 ) { - Debug( LDAP_DEBUG_ANY, "do_delete: root dse!\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_delete: root dse!\n", + op->o_log_prefix, 0, 0 ); /* protocolError would likely be a more appropriate error */ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot delete the root DSE" ); goto cleanup; } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { - Debug( LDAP_DEBUG_ANY, "do_delete: subschema subentry!\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_delete: subschema subentry!\n", + op->o_log_prefix, 0, 0 ); /* protocolError would likely be a more appropriate error */ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot delete the root DSE" ); goto cleanup; } - Statslog( LDAP_DEBUG_STATS, "%s DEL dn=\"%s\"\n", - op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); - op->o_bd = frontendDB; rs->sr_err = frontendDB->be_delete( op, rs ); @@ -107,17 +111,14 @@ int fe_op_delete( Operation *op, SlapReply *rs ) { struct berval pdn = BER_BVNULL; - int manageDSAit; BackendDB *op_be, *bd = op->o_bd; - manageDSAit = get_manageDSAit( op ); - /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 1 ); + op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, @@ -139,7 +140,7 @@ fe_op_delete( Operation *op, SlapReply *rs ) /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ @@ -168,15 +169,8 @@ fe_op_delete( Operation *op, SlapReply *rs ) struct berval org_dn = BER_BVNULL; struct berval org_ndn = BER_BVNULL; int org_managedsait; - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; op->o_bd = op_be; - - if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ) { - cb.sc_next = op->o_callback; - op->o_callback = &cb; - } - op->o_bd->be_delete( op, rs ); org_req_dn = op->o_req_dn; diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 509adb76e3..b71dfc95f6 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -228,81 +228,62 @@ rdnValidate( * Note: the sorting can be slightly improved by sorting first * by attribute type length, then by alphabetical order. * - * uses a linear search; should be fine since the number of AVAs in + * uses an insertion sort; should be fine since the number of AVAs in * a RDN should be limited. */ -static void -AVA_Sort( LDAPRDN rdn, int iAVA ) +static int +AVA_Sort( LDAPRDN rdn, int nAVAs ) { + LDAPAVA *ava_i; int i; - LDAPAVA *ava_in = rdn[ iAVA ]; assert( rdn != NULL ); - assert( ava_in != NULL ); - - for ( i = 0; i < iAVA; i++ ) { - LDAPAVA *ava = rdn[ i ]; - int a, j; - assert( ava != NULL ); + for ( i = 1; i < nAVAs; i++ ) { + LDAPAVA *ava_j; + int j; - a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val ); + ava_i = rdn[ i ]; + for ( j = i-1; j >=0; j-- ) { + int a; - if ( a > 0 ) { - break; - } + ava_j = rdn[ j ]; + a = strcmp( ava_i->la_attr.bv_val, ava_j->la_attr.bv_val ); - while ( a == 0 ) { - int v, d; + if ( a == 0 ) { + int d; - d = ava_in->la_value.bv_len - ava->la_value.bv_len; + d = ava_i->la_value.bv_len - ava_j->la_value.bv_len; - v = memcmp( ava_in->la_value.bv_val, - ava->la_value.bv_val, - d <= 0 ? ava_in->la_value.bv_len - : ava->la_value.bv_len ); + a = memcmp( ava_i->la_value.bv_val, + ava_j->la_value.bv_val, + d <= 0 ? ava_i->la_value.bv_len + : ava_j->la_value.bv_len ); - if ( v == 0 && d != 0 ) { - v = d; + if ( a == 0 ) { + a = d; + } } + /* Duplicates are not allowed */ + if ( a == 0 ) + return LDAP_INVALID_DN_SYNTAX; - if ( v <= 0 ) { - /* - * got it! - */ + if ( a > 0 ) break; - } - if ( ++i == iAVA ) { - /* - * already sorted - */ - return; - } - - ava = rdn[ i ]; - a = strcmp( ava_in->la_attr.bv_val, - ava->la_attr.bv_val ); - } - - /* - * move ahead - */ - for ( j = iAVA; j > i; j-- ) { - rdn[ j ] = rdn[ j - 1 ]; + rdn[ j+1 ] = rdn[ j ]; } - rdn[ i ] = ava_in; - - return; + rdn[ j+1 ] = ava_i; } + return LDAP_SUCCESS; } static int LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx ) { - int rc; - int iAVA; + int rc, iAVA, do_sort = 0; + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { LDAPAVA *ava = rdn[ iAVA ]; AttributeDescription *ad; @@ -311,7 +292,6 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx ) slap_syntax_transform_func *transf = NULL; MatchingRule *mr = NULL; struct berval bv = BER_BVNULL; - int do_sort = 0; assert( ava != NULL ); @@ -415,10 +395,14 @@ LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx ) ava->la_value = bv; ava->la_flags |= LDAP_AVA_FREE_VALUE; } + } + rc = LDAP_SUCCESS; - if( do_sort ) AVA_Sort( rdn, iAVA ); + if ( do_sort ) { + rc = AVA_Sort( rdn, iAVA ); } - return LDAP_SUCCESS; + + return rc; } /* @@ -1257,7 +1241,6 @@ int register_certificate_map_function(SLAP_CERT_MAP_FN *fn) return -1; } -#ifdef HAVE_TLS /* * Convert an X.509 DN into a normalized LDAP DN */ @@ -1274,6 +1257,7 @@ dnX509normalize( void *x509_name, struct berval *out ) return rc; } +#ifdef HAVE_TLS /* * Get the TLS session's peer's DN into a normalized LDAP DN */ diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c index dda4e18502..660bcb676b 100644 --- a/servers/slapd/entry.c +++ b/servers/slapd/entry.c @@ -100,6 +100,8 @@ str2entry( char *s ) return str2entry2( s, 1 ); } +#define bvcasematch(bv1, bv2) (ber_bvstrcasecmp(bv1, bv2) == 0) + Entry * str2entry2( char *s, int checkvals ) { @@ -166,6 +168,11 @@ str2entry2( char *s, int checkvals ) break; } i++; + if (i >= lines) { + Debug( LDAP_DEBUG_TRACE, + "<= str2entry ran past end of entry\n", 0, 0, 0 ); + goto fail; + } rc = ldif_parse_line2( s, type+i, vals+i, &freev ); freeval[i] = freev; @@ -175,9 +182,7 @@ str2entry2( char *s, int checkvals ) continue; } - if ( type[i].bv_len == dn_bv.bv_len && - strcasecmp( type[i].bv_val, dn_bv.bv_val ) == 0 ) { - + if ( bvcasematch( &type[i], &dn_bv ) ) { if ( e->e_dn != NULL ) { Debug( LDAP_DEBUG_ANY, "str2entry: " "entry %ld has multiple DNs \"%s\" and \"%s\"\n", @@ -207,8 +212,6 @@ str2entry2( char *s, int checkvals ) goto fail; } -#define bvcasematch(bv1, bv2) ( ((bv1)->bv_len == (bv2)->bv_len) && (strncasecmp((bv1)->bv_val, (bv2)->bv_val, (bv1)->bv_len) == 0) ) - /* Make sure all attributes with multiple values are contiguous */ if ( checkvals ) { int j, k; @@ -260,6 +263,16 @@ str2entry2( char *s, int checkvals ) goto fail; } } + + /* require ';binary' when appropriate (ITS#5071) */ + if ( slap_syntax_is_binary( ad->ad_type->sat_syntax ) && !slap_ad_is_binary( ad ) ) { + Debug( LDAP_DEBUG_ANY, + "str2entry: attributeType %s #%d: " + "needs ';binary' transfer as per syntax %s\n", + ad->ad_cname.bv_val, 0, + ad->ad_type->sat_syntax->ssyn_oid ); + goto fail; + } } if (( ad_prev && ad != ad_prev ) || ( i == lines )) { @@ -297,6 +310,14 @@ str2entry2( char *s, int checkvals ) if ( i == lines ) break; } + if ( BER_BVISNULL( &vals[i] ) ) { + Debug( LDAP_DEBUG_ANY, + "str2entry: attributeType %s #%d: " + "no value\n", + ad->ad_cname.bv_val, attr_cnt, 0 ); + goto fail; + } + if( slapMode & SLAP_TOOL_MODE ) { struct berval pval; slap_syntax_validate_func *validate = diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c index 38bb96c147..2338b215f5 100644 --- a/servers/slapd/extended.c +++ b/servers/slapd/extended.c @@ -123,19 +123,20 @@ do_extended( ber_tag_t tag; ber_len_t len; - Debug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s do_extended\n", + op->o_log_prefix, 0, 0 ); if( op->o_protocol < LDAP_VERSION3 ) { - Debug( LDAP_DEBUG_ANY, - "do_extended: protocol version (%d) too low\n", - op->o_protocol, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_extended: protocol version (%d) too low\n", + op->o_log_prefix, op->o_protocol, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "requires LDAPv3" ); rs->sr_err = SLAPD_DISCONNECT; goto done; } if ( ber_scanf( op->o_ber, "{m" /*}*/, &op->ore_reqoid ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_extended: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto done; @@ -145,7 +146,8 @@ do_extended( if( ber_peek_tag( op->o_ber, &len ) == LDAP_TAG_EXOP_REQ_VALUE ) { if( ber_scanf( op->o_ber, "m", &reqdata ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_extended: ber_scanf failed\n", 0, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_extended: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto done; @@ -153,14 +155,16 @@ do_extended( } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_extended: get_ctrls failed\n", 0, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_extended: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); return rs->sr_err; } + Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n", + op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 ); + /* check for controls inappropriate for all extended operations */ if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) { - Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n", - op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 ); send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "manageDSAit control inappropriate" ); @@ -203,10 +207,8 @@ fe_extended( Operation *op, SlapReply *rs ) ext = find_extop(supp_ext_list, &op->ore_reqoid ); if ( ext == NULL ) { - Statslog( LDAP_DEBUG_STATS, "%s EXT oid=%s\n", - op->o_log_prefix, op->ore_reqoid.bv_val, 0, 0, 0 ); - Debug( LDAP_DEBUG_ANY, "do_extended: unsupported operation \"%s\"\n", - op->ore_reqoid.bv_val, 0 ,0 ); + Debug( LDAP_DEBUG_ANY, "%s do_extended: unsupported operation \"%s\"\n", + op->o_log_prefix, op->ore_reqoid.bv_val, 0 ); send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "unsupported extended operation" ); goto done; diff --git a/servers/slapd/filter.c b/servers/slapd/filter.c index f7b6821482..d3ceb0b8a8 100644 --- a/servers/slapd/filter.c +++ b/servers/slapd/filter.c @@ -618,16 +618,16 @@ simple: len = fstr->bv_len; filter_escape_value_x( &f->f_sub_initial, &tmp, op->o_tmpmemctx ); - tmplen = tmp.bv_len ? tmp.bv_len : STRLENOF( "(null)" ); + tmplen = tmp.bv_len; fstr->bv_len += tmplen; fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, op->o_tmpmemctx ); - snprintf( &fstr->bv_val[len-2], + snprintf( &fstr->bv_val[len - 2], tmplen + STRLENOF( /*(*/ "*)" ) + 1, /* "(attr=" */ "%s*)", - tmp.bv_len ? tmp.bv_val : "(null)"); + tmp.bv_len ? tmp.bv_val : ""); ber_memfree_x( tmp.bv_val, op->o_tmpmemctx ); } @@ -639,16 +639,16 @@ simple: len = fstr->bv_len; filter_escape_value_x( &f->f_sub_any[i], &tmp, op->o_tmpmemctx ); - tmplen = tmp.bv_len ? tmp.bv_len : STRLENOF( "(null)" ); + tmplen = tmp.bv_len; fstr->bv_len += tmplen + STRLENOF( /*(*/ ")" ); fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, op->o_tmpmemctx ); - snprintf( &fstr->bv_val[len-1], + snprintf( &fstr->bv_val[len - 1], tmplen + STRLENOF( /*(*/ "*)" ) + 1, /* "(attr=[init]*[any*]" */ "%s*)", - tmp.bv_len ? tmp.bv_val : "(null)"); + tmp.bv_len ? tmp.bv_val : ""); ber_memfree_x( tmp.bv_val, op->o_tmpmemctx ); } } @@ -659,16 +659,16 @@ simple: len = fstr->bv_len; filter_escape_value_x( &f->f_sub_final, &tmp, op->o_tmpmemctx ); - tmplen = tmp.bv_len ? tmp.bv_len : STRLENOF( "(null)" ); + tmplen = tmp.bv_len; fstr->bv_len += tmplen; fstr->bv_val = op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, op->o_tmpmemctx ); - snprintf( &fstr->bv_val[len-1], + snprintf( &fstr->bv_val[len - 1], tmplen + STRLENOF( /*(*/ ")" ) + 1, /* "(attr=[init*][any*]" */ "%s)", - tmp.bv_len ? tmp.bv_val : "(null)"); + tmp.bv_len ? tmp.bv_val : ""); ber_memfree_x( tmp.bv_val, op->o_tmpmemctx ); } diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c index 336476a8fd..d1fb4856e3 100644 --- a/servers/slapd/filterentry.c +++ b/servers/slapd/filterentry.c @@ -583,7 +583,7 @@ test_ava_filter( if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { MatchingRule *mr; - int rc, match; + int match; const char *text; if( type != LDAP_FILTER_EQUALITY && @@ -729,7 +729,7 @@ test_ava_filter( } else #endif { - ret = value_match( &match, a->a_desc, mr, use, + ret = ordered_value_match( &match, a->a_desc, mr, use, bv, &ava->aa_value, &text ); } diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 3cff69e3e6..5666a49b99 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -69,8 +69,6 @@ ldap_pvt_thread_mutex_t gmtime_mutex; slap_counters_t slap_counters; -ldap_pvt_thread_mutex_t replog_mutex; - static const char* slap_name = NULL; int slapMode = SLAP_UNDEFINED_MODE; @@ -94,6 +92,8 @@ slap_init( int mode, const char *name ) slapMode = mode; + slap_op_init(); + #ifdef SLAPD_MODULES if ( module_init() != 0 ) { slap_debug |= LDAP_DEBUG_NONE; @@ -135,7 +135,6 @@ slap_init( int mode, const char *name ) ldap_pvt_thread_pool_init( &connection_pool, connection_pool_max, 0); - ldap_pvt_thread_mutex_init( &replog_mutex ); ldap_pvt_thread_mutex_init( &slap_counters.sc_sent_mutex ); ldap_pvt_thread_mutex_init( &slap_counters.sc_ops_mutex ); @@ -310,8 +309,10 @@ int slap_destroy(void) } + slap_op_destroy(); + ldap_pvt_thread_destroy(); - /* should destory the above mutex */ + /* should destroy the above mutex */ return rc; } diff --git a/servers/slapd/ldapsync.c b/servers/slapd/ldapsync.c index 16abf885b0..99905ac677 100644 --- a/servers/slapd/ldapsync.c +++ b/servers/slapd/ldapsync.c @@ -120,20 +120,37 @@ slap_sync_cookie_free( } int -slap_parse_csn_sid( struct berval *csn ) +slap_parse_csn_sid( struct berval *csnp ) { char *p, *q; + struct berval csn = *csnp; int i; - p = memchr( csn->bv_val, '#', csn->bv_len ); - if ( p ) - p = strchr( p+1, '#' ); + p = ber_bvchr( &csn, '#' ); if ( !p ) return -1; p++; - i = strtoul( p, &q, 10 ); - if ( p == q || i > SLAP_SYNC_SID_MAX ) + csn.bv_len -= p - csn.bv_val; + csn.bv_val = p; + + p = ber_bvchr( &csn, '#' ); + if ( !p ) + return -1; + p++; + csn.bv_len -= p - csn.bv_val; + csn.bv_val = p; + + q = ber_bvchr( &csn, '#' ); + if ( !q ) + return -1; + + csn.bv_len = q - p; + + i = (int)strtoul( p, &q, 16 ); + if ( p == q || q != p + csn.bv_len || i > SLAP_SYNC_SID_MAX ) { i = -1; + } + return i; } @@ -141,7 +158,6 @@ int * slap_parse_csn_sids( BerVarray csns, int numcsns, void *memctx ) { int i, *ret; - char *p, *q; ret = slap_sl_malloc( numcsns * sizeof(int), memctx ); for ( i=0; io_bd = select_backend( &op->o_req_ndn, manageDSAit, 1 ); + op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, @@ -244,7 +243,7 @@ fe_op_modify( Operation *op, SlapReply *rs ) /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ @@ -287,7 +286,6 @@ fe_op_modify( Operation *op, SlapReply *rs ) */ if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; op->o_bd = op_be; @@ -299,13 +297,6 @@ fe_op_modify( Operation *op, SlapReply *rs ) goto cleanup; } } - - if ( !repl_user ) { - /* but multimaster slapd logs only the ones - * not from a replicator user */ - cb.sc_next = op->o_callback; - op->o_callback = &cb; - } op->o_bd->be_modify( op, rs ); } else { /* send a referral */ @@ -695,7 +686,7 @@ int slap_mods_check( MatchingRule *mr = ad->ad_type->sat_equality; int istack[sizeof(int)*16]; - int i,j,k,l,ir,jstack, rc, match, *ix, itmp; + int i, j, k, l, ir, jstack, match, *ix, itmp; struct berval a, *cv; /* If PRESERVE_ORDER is defined only the index array is sorted; the @@ -886,6 +877,7 @@ void slap_mods_opattrs( timestamp.bv_val = timebuf; for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { if ( (*modtail)->sml_op != LDAP_MOD_ADD && + (*modtail)->sml_op != SLAP_MOD_SOFTADD && (*modtail)->sml_op != LDAP_MOD_REPLACE ) { continue; @@ -1011,9 +1003,9 @@ slap_parse_modlist( ber_tag_t tag; ber_len_t len; char *last; - Modifications **modtail = &ms->rs_modlist; + Modifications **modtail = &ms->rs_mods.rs_modlist; - ms->rs_modlist = NULL; + ms->rs_mods.rs_modlist = NULL; ms->rs_increment = 0; rs->sr_err = LDAP_SUCCESS; @@ -1049,10 +1041,6 @@ slap_parse_modlist( switch( mop ) { case LDAP_MOD_ADD: if ( mod->sml_values == NULL ) { - Debug( LDAP_DEBUG_ANY, "slap_parse_modlist: " - "modify/add operation (%ld) requires values\n", - (long) mop, 0, 0 ); - rs->sr_text = "modify/add operation requires values"; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; @@ -1068,20 +1056,12 @@ slap_parse_modlist( if( op->o_protocol >= LDAP_VERSION3 ) { ms->rs_increment++; if ( mod->sml_values == NULL ) { - Debug( LDAP_DEBUG_ANY, "slap_parse_modlist: " - "modify/increment operation (%ld) requires value\n", - (long) mop, 0, 0 ); - rs->sr_text = "modify/increment operation requires value"; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; } if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) { - Debug( LDAP_DEBUG_ANY, "slap_parse_modlist: modify/increment " - "operation (%ld) requires single value\n", - (long) mop, 0, 0 ); - rs->sr_text = "modify/increment operation requires single value"; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; @@ -1092,10 +1072,6 @@ slap_parse_modlist( /* fall thru */ default: - Debug( LDAP_DEBUG_ANY, "slap_parse_modlist: " - "unrecognized modify operation (%ld)\n", - (long) mop, 0, 0 ); - rs->sr_text = "unrecognized modify operation"; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; @@ -1107,8 +1083,8 @@ slap_parse_modlist( done: if ( rs->sr_err != LDAP_SUCCESS ) { - slap_mods_free( ms->rs_modlist, 1 ); - ms->rs_modlist = NULL; + slap_mods_free( ms->rs_mods.rs_modlist, 1 ); + ms->rs_mods.rs_modlist = NULL; ms->rs_increment = 0; } diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 0e511a761e..3aae6ac444 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -57,9 +57,8 @@ do_modrdn( ber_len_t length; - Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 ); - - + Debug( LDAP_DEBUG_TRACE, "%s do_modrdn\n", + op->o_log_prefix, 0, 0 ); /* * Parse the modrdn request. It looks like this: * @@ -74,8 +73,8 @@ do_modrdn( if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 ); - + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } @@ -84,12 +83,12 @@ do_modrdn( if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) { if ( op->o_protocol < LDAP_VERSION3 ) { - /* Conection record indicates v2 but field + /* Connection record indicates v2 but field * newSuperior is present: report error. */ Debug( LDAP_DEBUG_ANY, - "modrdn(v2): invalid field newSuperior!\n", - 0, 0, 0 ); + "%s do_modrdn: newSuperior requires LDAPv3\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" ); @@ -100,8 +99,8 @@ do_modrdn( if ( ber_scanf( op->o_ber, "m", &newSuperior ) == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "ber_scanf(\"m\") failed\n", - 0, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); @@ -118,8 +117,8 @@ do_modrdn( newSuperior.bv_len ? newSuperior.bv_val : "" ); if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) { - Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 ); - + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n", + op->o_log_prefix, 0, 0 ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; @@ -127,16 +126,16 @@ do_modrdn( } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 ); - + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: get_ctrls failed\n", + op->o_log_prefix, 0, 0 ); /* get_ctrls has sent results. Now clean up. */ goto cleanup; } rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "do_modrdn: invalid dn (%s)\n", dn.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid dn (%s)\n", + op->o_log_prefix, dn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } @@ -145,16 +144,15 @@ do_modrdn( rs->sr_err = dnPrettyNormal( NULL, &newrdn, &op->orr_newrdn, &op->orr_nnewrdn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, - "do_modrdn: invalid newrdn (%s)\n", newrdn.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newrdn (%s)\n", + op->o_log_prefix, newrdn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" ); goto cleanup; } if( rdn_validate( &op->orr_newrdn ) != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid rdn (%s)\n", - op->orr_newrdn.bv_val, 0, 0 ); - + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid rdn (%s)\n", + op->o_log_prefix, op->orr_newrdn.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" ); goto cleanup; } @@ -164,13 +162,16 @@ do_modrdn( &nnewSuperior, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, - "do_modrdn: invalid newSuperior (%s)\n", - newSuperior.bv_val, 0, 0 ); + "%s do_modrdn: invalid newSuperior (%s)\n", + op->o_log_prefix, newSuperior.bv_val, 0 ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" ); goto cleanup; } } + Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n", + op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); + op->orr_deleteoldrdn = deloldrdn; op->orr_modlist = NULL; @@ -214,37 +215,31 @@ int fe_op_modrdn( Operation *op, SlapReply *rs ) { Backend *newSuperior_be = NULL; - int manageDSAit; struct berval pdn = BER_BVNULL; BackendDB *op_be, *bd = op->o_bd; if( op->o_req_ndn.bv_len == 0 ) { - Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 ); - + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n", + op->o_log_prefix, 0, 0 ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot rename the root DSE" ); goto cleanup; } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { - Debug( LDAP_DEBUG_ANY, "do_modrdn: subschema subentry: %s (%ld)\n", - frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len, 0 ); + Debug( LDAP_DEBUG_ANY, "%s do_modrdn: subschema subentry: %s (%ld)\n", + op->o_log_prefix, frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot rename subschema subentry" ); goto cleanup; } - Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n", - op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); - - manageDSAit = get_manageDSAit( op ); - /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 1 ); + op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, @@ -266,7 +261,7 @@ fe_op_modrdn( Operation *op, SlapReply *rs ) /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { - op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ @@ -284,7 +279,7 @@ fe_op_modrdn( Operation *op, SlapReply *rs ) * the same backend, otherwise we return an error. */ if( op->orr_newSup ) { - newSuperior_be = select_backend( op->orr_nnewSup, 0, 0 ); + newSuperior_be = select_backend( op->orr_nnewSup, 0 ); if ( newSuperior_be != op->o_bd ) { /* newSuperior is in different backend */ @@ -306,15 +301,7 @@ fe_op_modrdn( Operation *op, SlapReply *rs ) int repl_user = be_isupdate( op ); if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { - slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; - op->o_bd = op_be; - - if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ) - { - cb.sc_next = op->o_callback; - op->o_callback = &cb; - } op->o_bd->be_modrdn( op, rs ); if ( op->o_bd->be_delete ) { @@ -349,7 +336,7 @@ fe_op_modrdn( Operation *op, SlapReply *rs ) } } op->o_managedsait = org_managedsait; - op->o_dn = org_dn; + op->o_dn = org_dn; op->o_ndn = org_ndn; op->o_req_dn = org_req_dn; op->o_req_ndn = org_req_ndn; @@ -399,8 +386,9 @@ slap_modrdn2mods( if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, - "slap_modrdn2mods: can't figure out " - "type(s)/value(s) of newrdn\n", 0, 0, 0 ); + "%s slap_modrdn2mods: can't figure out " + "type(s)/value(s) of newrdn\n", + op->o_log_prefix, 0, 0 ); rs->sr_err = LDAP_INVALID_DN_SYNTAX; rs->sr_text = "unknown type(s) used in RDN"; goto done; @@ -410,8 +398,9 @@ slap_modrdn2mods( if ( ldap_bv2rdn_x( &op->o_req_dn, &old_rdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, - "slap_modrdn2mods: can't figure out " - "type(s)/value(s) of oldrdn\n", 0, 0, 0 ); + "%s slap_modrdn2mods: can't figure out " + "type(s)/value(s) of oldrdn\n", + op->o_log_prefix, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "cannot parse RDN from old DN"; goto done; @@ -428,9 +417,10 @@ slap_modrdn2mods( if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "slap_modrdn2mods: %s: %s (new)\n", + "%s slap_modrdn2mods: %s: %s (new)\n", + op->o_log_prefix, rs->sr_text, - new_rdn[ a_cnt ]->la_attr.bv_val, 0 ); + new_rdn[ a_cnt ]->la_attr.bv_val ); goto done; } @@ -468,10 +458,10 @@ slap_modrdn2mods( rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, - "slap_modrdn2mods: %s: %s (old)\n", + "%s slap_modrdn2mods: %s: %s (old)\n", + op->o_log_prefix, rs->sr_text, - old_rdn[d_cnt]->la_attr.bv_val, - 0 ); + old_rdn[d_cnt]->la_attr.bv_val ); goto done; } diff --git a/servers/slapd/module.c b/servers/slapd/module.c index ebeb50b6e7..71e1b22200 100644 --- a/servers/slapd/module.c +++ b/servers/slapd/module.c @@ -68,7 +68,8 @@ int module_init (void) return -1; } - return 0; + + return module_path( LDAP_MODULEDIR ); } int module_kill (void) diff --git a/servers/slapd/mr.c b/servers/slapd/mr.c index 85d60bf62c..f85c08af06 100644 --- a/servers/slapd/mr.c +++ b/servers/slapd/mr.c @@ -30,9 +30,9 @@ struct mindexrec { }; static Avlnode *mr_index = NULL; -static LDAP_SLIST_HEAD(MRList, slap_matching_rule) mr_list +static LDAP_SLIST_HEAD(MRList, MatchingRule) mr_list = LDAP_SLIST_HEAD_INITIALIZER(&mr_list); -static LDAP_SLIST_HEAD(MRUList, slap_matching_rule_use) mru_list +static LDAP_SLIST_HEAD(MRUList, MatchingRuleUse) mru_list = LDAP_SLIST_HEAD_INITIALIZER(&mru_list); static int @@ -145,6 +145,67 @@ mr_insert( return 0; } +int +mr_make_syntax_compat_with_mr( + Syntax *syn, + MatchingRule *mr ) +{ + int n = 0; + + assert( syn != NULL ); + assert( mr != NULL ); + + if ( mr->smr_compat_syntaxes ) { + /* count esisting */ + for ( n = 0; + mr->smr_compat_syntaxes[ n ]; + n++ ) + { + if ( mr->smr_compat_syntaxes[ n ] == syn ) { + /* already compatible; mmmmh... */ + return 1; + } + } + } + + mr->smr_compat_syntaxes = ch_realloc( + mr->smr_compat_syntaxes, + sizeof( Syntax * )*(n + 2) ); + mr->smr_compat_syntaxes[ n ] = syn; + mr->smr_compat_syntaxes[ n + 1 ] = NULL; + + return 0; +} + +int +mr_make_syntax_compat_with_mrs( + const char *syntax, + char *const *mrs ) +{ + int r, rc = 0; + Syntax *syn; + + assert( syntax != NULL ); + assert( mrs != NULL ); + + syn = syn_find( syntax ); + if ( syn == NULL ) { + return -1; + } + + for ( r = 0; mrs[ r ] != NULL; r++ ) { + MatchingRule *mr = mr_find( mrs[ r ] ); + if ( mr == NULL ) { + /* matchingRule not found -- ignore by now */ + continue; + } + + rc += mr_make_syntax_compat_with_mr( syn, mr ); + } + + return rc; +} + int mr_add( LDAPMatchingRule *mr, @@ -316,7 +377,8 @@ matching_rule_use_init( void ) LDAP_SLIST_FOREACH( mr, &mr_list, smr_next ) { AttributeType *at; - MatchingRuleUse mru_storage, *mru = &mru_storage; + MatchingRuleUse mru_storage = { 0 }, + *mru = &mru_storage; char **applies_oids = NULL; @@ -341,8 +403,6 @@ matching_rule_use_init( void ) continue; } - memset( mru, 0, sizeof( MatchingRuleUse ) ); - /* * Note: we're using the same values of the corresponding * MatchingRule structure; maybe we'd copy them ... @@ -396,13 +456,16 @@ matching_rule_use_init( void ) return( 0 ); } -int mr_usable_with_at( - MatchingRule *mr, - AttributeType *at ) +int +mr_usable_with_at( + MatchingRule *mr, + AttributeType *at ) { - if( mr->smr_usage & SLAP_MR_EXT && ( + if ( ( mr->smr_usage & SLAP_MR_EXT ) && ( mr->smr_syntax == at->sat_syntax || - mr == at->sat_equality || mr == at->sat_approx ) ) + mr == at->sat_equality || + mr == at->sat_approx || + syn_is_sup( at->sat_syntax, mr->smr_syntax ) ) ) { return 1; } diff --git a/servers/slapd/oc.c b/servers/slapd/oc.c index ef52fc8695..42879ee76e 100644 --- a/servers/slapd/oc.c +++ b/servers/slapd/oc.c @@ -37,16 +37,16 @@ int is_object_subclass( sup->soc_oid, sub->soc_oid, sup == sub ); #endif - if( sup == sub ) { + if ( sup == sub ) { return 1; } - if( sub->soc_sups == NULL ) { + if ( sub->soc_sups == NULL ) { return 0; } - for( i=0; sub->soc_sups[i] != NULL; i++ ) { - if( is_object_subclass( sup, sub->soc_sups[i] ) ) { + for ( i = 0; sub->soc_sups[i] != NULL; i++ ) { + if ( is_object_subclass( sup, sub->soc_sups[i] ) ) { return 1; } } @@ -71,11 +71,11 @@ int is_entry_objectclass( assert( !( e == NULL || oc == NULL ) ); assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK ); - if( e == NULL || oc == NULL ) { + if ( e == NULL || oc == NULL ) { return 0; } - if( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) ) + if ( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) ) { /* flags are set, use them */ return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0; @@ -85,7 +85,7 @@ int is_entry_objectclass( * find objectClass attribute */ attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); - if( attr == NULL ) { + if ( attr == NULL ) { /* no objectClass attribute */ Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") " "no objectClass attribute\n", @@ -95,7 +95,7 @@ int is_entry_objectclass( return 0; } - for( bv=attr->a_vals; bv->bv_val; bv++ ) { + for ( bv = attr->a_vals; bv->bv_val; bv++ ) { ObjectClass *objectClass = oc_bvfind( bv ); if ( objectClass == NULL ) { @@ -132,7 +132,7 @@ struct oindexrec { static Avlnode *oc_index = NULL; static Avlnode *oc_cache = NULL; -static LDAP_STAILQ_HEAD(OCList, slap_object_class) oc_list +static LDAP_STAILQ_HEAD(OCList, ObjectClass) oc_list = LDAP_STAILQ_HEAD_INITIALIZER(oc_list); ObjectClass *oc_sys_tail; @@ -193,7 +193,7 @@ oc_bvfind( struct berval *ocname ) return( NULL ); } -static LDAP_STAILQ_HEAD(OCUList, slap_object_class) oc_undef_list +static LDAP_STAILQ_HEAD(OCUList, ObjectClass) oc_undef_list = LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list); ObjectClass * @@ -414,7 +414,7 @@ oc_delete( ObjectClass *oc ) { oc->soc_flags |= SLAP_OC_DELETED; - LDAP_STAILQ_REMOVE(&oc_list,oc,slap_object_class,soc_next); + LDAP_STAILQ_REMOVE(&oc_list, oc, ObjectClass, soc_next); oc_delete_names( oc ); } diff --git a/servers/slapd/oidm.c b/servers/slapd/oidm.c index 646574a378..287937f03c 100644 --- a/servers/slapd/oidm.c +++ b/servers/slapd/oidm.c @@ -26,7 +26,7 @@ #include "lutil.h" #include "config.h" -static LDAP_STAILQ_HEAD(OidMacroList, slap_oid_macro) om_list +static LDAP_STAILQ_HEAD(OidMacroList, OidMacro) om_list = LDAP_STAILQ_HEAD_INITIALIZER(om_list); OidMacro *om_sys_tail; @@ -105,22 +105,22 @@ parse_oidm( oidv = oidm_find( c->argv[2] ); if( !oidv ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID %s not recognized", c->argv[0], c->argv[2] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s %s\n", c->log, c->msg, 0 ); + "%s %s\n", c->log, c->cr_msg, 0 ); return 1; } oid = oidm_find( c->argv[1] ); if( oid != NULL ) { int rc; - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: \"%s\" previously defined \"%s\"", c->argv[0], c->argv[1], oid ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s %s\n", c->log, c->msg, 0 ); + "%s %s\n", c->log, c->cr_msg, 0 ); /* Allow duplicate if the definition is identical */ rc = strcmp( oid, oidv ) != 0; SLAP_FREE( oid ); @@ -131,10 +131,10 @@ parse_oidm( om = (OidMacro *) SLAP_CALLOC( sizeof(OidMacro), 1 ); if( om == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: SLAP_CALLOC failed", c->argv[0] ); Debug( LDAP_DEBUG_ANY, - "%s %s\n", c->log, c->msg, 0 ); + "%s %s\n", c->log, c->cr_msg, 0 ); if ( oidv != c->argv[2] ) SLAP_FREE( oidv ); return 1; diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index 601ab81259..b5b2f3d1e6 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -38,7 +38,7 @@ #endif static ldap_pvt_thread_mutex_t slap_op_mutex; -static LDAP_STAILQ_HEAD(s_o, slap_op) slap_free_ops; +static LDAP_STAILQ_HEAD(s_o, Operation) slap_free_ops; static time_t last_time; static int last_incr; @@ -74,6 +74,8 @@ slap_op_groups_free( Operation *op ) void slap_op_free( Operation *op ) { + OperationBuffer *opbuf; + assert( LDAP_STAILQ_NEXT(op, o_next) == NULL ); if ( op->o_ber != NULL ) { @@ -109,9 +111,10 @@ slap_op_free( Operation *op ) #endif /* defined( LDAP_SLAPI ) */ - memset( op, 0, sizeof(Operation) + sizeof(Opheader) + SLAP_MAX_CIDS * sizeof(void *) ); - op->o_hdr = (Opheader *)(op+1); - op->o_controls = (void **)(op->o_hdr+1); + opbuf = (OperationBuffer *) op; + memset( opbuf, 0, sizeof(*opbuf) ); + op->o_hdr = &opbuf->ob_hdr; + op->o_controls = opbuf->ob_controls; ldap_pvt_thread_mutex_lock( &slap_op_mutex ); LDAP_STAILQ_INSERT_HEAD( &slap_free_ops, op, o_next ); @@ -149,10 +152,9 @@ slap_op_alloc( ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); if (!op) { - op = (Operation *) ch_calloc( 1, sizeof(Operation) - + sizeof(Opheader) + SLAP_MAX_CIDS * sizeof(void *) ); - op->o_hdr = (Opheader *)(op + 1); - op->o_controls = (void **)(op->o_hdr+1); + op = (Operation *) ch_calloc( 1, sizeof(OperationBuffer) ); + op->o_hdr = &((OperationBuffer *) op)->ob_hdr; + op->o_controls = ((OperationBuffer *) op)->ob_controls; } op->o_ber = ber; diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in index a6d04ee1d9..3321f968a4 100644 --- a/servers/slapd/overlays/Makefile.in +++ b/servers/slapd/overlays/Makefile.in @@ -20,6 +20,7 @@ SRCS = overlays.c \ dds.c \ dyngroup.c \ dynlist.c \ + memberof.c \ pcache.c \ ppolicy.c \ refint.c \ @@ -30,9 +31,9 @@ SRCS = overlays.c \ translucent.c \ unique.c \ valsort.c -OBJS = overlays.o \ - statover.o \ - @SLAPD_STATIC_OVERLAYS@ +OBJS = statover.o \ + @SLAPD_STATIC_OVERLAYS@ \ + overlays.o # Add here the objs that are needed by overlays, but do not make it # into SLAPD_STATIC_OVERLAYS... @@ -76,6 +77,9 @@ dyngroup.la : dyngroup.lo dynlist.la : dynlist.lo $(LTLINK_MOD) -module -o $@ dynlist.lo version.lo $(LINK_LIBS) +memberof.la : memberof.lo + $(LTLINK_MOD) -module -o $@ memberof.lo version.lo $(LINK_LIBS) + pcache.la : pcache.lo $(LTLINK_MOD) -module -o $@ pcache.lo version.lo $(LINK_LIBS) diff --git a/servers/slapd/overlays/accesslog.c b/servers/slapd/overlays/accesslog.c index b23c421f1e..51813e6a8c 100644 --- a/servers/slapd/overlays/accesslog.c +++ b/servers/slapd/overlays/accesslog.c @@ -168,6 +168,7 @@ static ObjectClass *log_ocs[LOG_EN__COUNT], *log_container; #define LOG_SCHEMA_AT LOG_SCHEMA_ROOT ".1" #define LOG_SCHEMA_OC LOG_SCHEMA_ROOT ".2" +#define LOG_SCHEMA_SYN LOG_SCHEMA_ROOT ".3" static AttributeDescription *ad_reqDN, *ad_reqStart, *ad_reqEnd, *ad_reqType, *ad_reqSession, *ad_reqResult, *ad_reqAuthzID, *ad_reqControls, @@ -178,6 +179,31 @@ static AttributeDescription *ad_reqDN, *ad_reqStart, *ad_reqEnd, *ad_reqType, *ad_reqId, *ad_reqMessage, *ad_reqVersion, *ad_reqDerefAliases, *ad_reqReferral, *ad_reqOld, *ad_auditContext; +static int +logSchemaControlValidate( + Syntax *syntax, + struct berval *val ); + +char *mrControl[] = { + "objectIdentifierFirstComponentMatch", + NULL +}; + +static struct { + char *oid; + slap_syntax_defs_rec syn; + char **mrs; +} lsyntaxes[] = { + { LOG_SCHEMA_SYN ".1" , + { "( " LOG_SCHEMA_SYN ".1 DESC 'Control' )", + SLAP_SYNTAX_HIDE, + NULL, + logSchemaControlValidate, + NULL }, + mrControl }, + { NULL } +}; + static struct { char *at; AttributeDescription **ad; @@ -231,10 +257,14 @@ static struct { "SUP labeledURI )", &ad_reqReferral }, { "( " LOG_SCHEMA_AT ".10 NAME 'reqControls' " "DESC 'Request controls' " - "SYNTAX OMsOctetString )", &ad_reqControls }, + "EQUALITY objectIdentifierFirstComponentMatch " + "SYNTAX " LOG_SCHEMA_SYN ".1 " + "X-ORDERED 'VALUES' )", &ad_reqControls }, { "( " LOG_SCHEMA_AT ".11 NAME 'reqRespControls' " "DESC 'Response controls of request' " - "SYNTAX OMsOctetString )", &ad_reqRespControls }, + "EQUALITY objectIdentifierFirstComponentMatch " + "SYNTAX " LOG_SCHEMA_SYN ".1 " + "X-ORDERED 'VALUES' )", &ad_reqRespControls }, { "( " LOG_SCHEMA_AT ".12 NAME 'reqId' " "DESC 'ID of Request to Abandon' " "EQUALITY integerMatch " @@ -561,7 +591,7 @@ accesslog_purge( void *ctx, void *arg ) Connection conn = {0}; OperationBuffer opbuf; - Operation *op = (Operation *) &opbuf; + Operation *op; SlapReply rs = {REP_RESULT}; slap_callback cb = { NULL, log_old_lookup, NULL, NULL }; Filter f; @@ -571,7 +601,8 @@ accesslog_purge( void *ctx, void *arg ) char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; time_t old = slap_get_time(); - connection_fake_init( &conn, op, ctx ); + connection_fake_init( &conn, &opbuf, ctx ); + op = &opbuf.ob_op; f.f_choice = LDAP_FILTER_LE; f.f_ava = &ava; @@ -655,10 +686,10 @@ log_cf_gen(ConfigArgs *c) value_add_one( &c->rvalue_vals, li->li_db->be_suffix ); value_add_one( &c->rvalue_nvals, li->li_db->be_nsuffix ); } else { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "accesslog: \"logdb \" must be specified" ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->value_dn.bv_val ); + c->log, c->cr_msg, c->value_dn.bv_val ); rc = 1; break; } @@ -766,13 +797,13 @@ log_cf_gen(ConfigArgs *c) switch( c->type ) { case LOG_DB: if ( CONFIG_ONLINE_ADD( c )) { - li->li_db = select_backend( &c->value_ndn, 0, 0 ); + li->li_db = select_backend( &c->value_ndn, 0 ); if ( !li->li_db ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> no matching backend found for suffix", c->argv[0] ); Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", - c->log, c->msg, c->value_dn.bv_val ); + c->log, c->cr_msg, c->value_dn.bv_val ); rc = 1; } ch_free( c->value_ndn.bv_val ); @@ -813,7 +844,7 @@ log_cf_gen(ConfigArgs *c) case LOG_OLD: li->li_oldf = str2filter( c->argv[1] ); if ( !li->li_oldf ) { - sprintf( c->msg, "bad filter!" ); + sprintf( c->cr_msg, "bad filter!" ); rc = 1; } break; @@ -830,10 +861,10 @@ log_cf_gen(ConfigArgs *c) la->next = li->li_oldattrs; li->li_oldattrs = la; } else { - snprintf( c->msg, sizeof( c->msg ), "%s <%s>: %s", + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s <%s>: %s", c->argv[0], c->argv[i], text ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s: %s\n", c->log, c->msg, 0 ); + "%s: %s\n", c->log, c->cr_msg, 0 ); rc = ARG_BAD_CONF; break; } @@ -846,7 +877,273 @@ log_cf_gen(ConfigArgs *c) return rc; } -static Entry *accesslog_entry( Operation *op, int logop, +static int +logSchemaControlValidate( + Syntax *syntax, + struct berval *valp ) +{ + struct berval val, bv; + int i; + int rc = LDAP_SUCCESS; + + assert( valp != NULL ); + + val = *valp; + + /* check minimal size */ + if ( val.bv_len < STRLENOF( "{*}" ) ) { + return LDAP_INVALID_SYNTAX; + } + + val.bv_len--; + + /* check SEQUENCE boundaries */ + if ( val.bv_val[ 0 ] != '{' /*}*/ || + val.bv_val[ val.bv_len ] != /*{*/ '}' ) + { + return LDAP_INVALID_SYNTAX; + } + + /* extract and check OID */ + for ( i = 1; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + bv.bv_val = &val.bv_val[ i ]; + + for ( i++; i < val.bv_len; i++ ) { + if ( ASCII_SPACE( val.bv_val[ i ] ) ) + { + break; + } + } + + bv.bv_len = &val.bv_val[ i ] - bv.bv_val; + + rc = numericoidValidate( NULL, &bv ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( i == val.bv_len ) { + return LDAP_SUCCESS; + } + + if ( val.bv_val[ i ] != ' ' ) { + return LDAP_INVALID_SYNTAX; + } + + for ( i++; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + if ( i == val.bv_len ) { + return LDAP_SUCCESS; + } + + /* extract and check criticality */ + if ( strncasecmp( &val.bv_val[ i ], "criticality ", STRLENOF( "criticality " ) ) == 0 ) + { + i += STRLENOF( "criticality " ); + for ( ; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + if ( i == val.bv_len ) { + return LDAP_INVALID_SYNTAX; + } + + bv.bv_val = &val.bv_val[ i ]; + + for ( ; i < val.bv_len; i++ ) { + if ( ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + bv.bv_len = &val.bv_val[ i ] - bv.bv_val; + + if ( !bvmatch( &bv, &slap_true_bv ) && !bvmatch( &bv, &slap_false_bv ) ) + { + return LDAP_INVALID_SYNTAX; + } + + if ( i == val.bv_len ) { + return LDAP_SUCCESS; + } + + if ( val.bv_val[ i ] != ' ' ) { + return LDAP_INVALID_SYNTAX; + } + + for ( i++; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + if ( i == val.bv_len ) { + return LDAP_SUCCESS; + } + } + + /* extract and check controlValue */ + if ( strncasecmp( &val.bv_val[ i ], "controlValue ", STRLENOF( "controlValue " ) ) == 0 ) + { + i += STRLENOF( "controlValue " ); + for ( ; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + if ( i == val.bv_len ) { + return LDAP_INVALID_SYNTAX; + } + + if ( val.bv_val[ i ] != '"' ) { + return LDAP_INVALID_SYNTAX; + } + + for ( ; i < val.bv_len; i++ ) { + if ( val.bv_val[ i ] == '"' ) { + break; + } + + if ( !ASCII_HEX( val.bv_val[ i ] ) ) { + return LDAP_INVALID_SYNTAX; + } + } + + if ( val.bv_val[ i ] != '"' ) { + return LDAP_INVALID_SYNTAX; + } + + for ( ; i < val.bv_len; i++ ) { + if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { + break; + } + } + + if ( i == val.bv_len ) { + return LDAP_SUCCESS; + } + } + + return LDAP_INVALID_SYNTAX; +} + +static int +accesslog_ctrls( + LDAPControl **ctrls, + BerVarray *valsp, + BerVarray *nvalsp, + void *memctx ) +{ + long i, rc = 0; + + assert( valsp != NULL ); + assert( ctrls != NULL ); + + *valsp = NULL; + *nvalsp = NULL; + + for ( i = 0; ctrls[ i ] != NULL; i++ ) { + struct berval idx, + oid, + noid, + bv; + char *ptr, + buf[ 32 ]; + + if ( ctrls[ i ]->ldctl_oid == NULL ) { + return LDAP_PROTOCOL_ERROR; + } + + idx.bv_len = snprintf( buf, sizeof( buf ), "{%ld}", i ); + idx.bv_val = buf; + + ber_str2bv( ctrls[ i ]->ldctl_oid, 0, 0, &oid ); + noid.bv_len = idx.bv_len + oid.bv_len; + ptr = noid.bv_val = ber_memalloc_x( noid.bv_len + 1, memctx ); + ptr = lutil_strcopy( ptr, idx.bv_val ); + ptr = lutil_strcopy( ptr, oid.bv_val ); + + bv.bv_len = idx.bv_len + STRLENOF( "{}" ) + oid.bv_len; + + if ( ctrls[ i ]->ldctl_iscritical ) { + bv.bv_len += STRLENOF( " criticality TRUE" ); + } + + if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { + bv.bv_len += STRLENOF( " controlValue \"\"" ) + + 2 * ctrls[ i ]->ldctl_value.bv_len; + } + + ptr = bv.bv_val = ber_memalloc_x( bv.bv_len + 1, memctx ); + if ( ptr == NULL ) { + ber_bvarray_free( *valsp ); + *valsp = NULL; + ber_bvarray_free( *nvalsp ); + *nvalsp = NULL; + return LDAP_OTHER; + } + + ptr = lutil_strcopy( ptr, idx.bv_val ); + + *ptr++ = '{' /*}*/ ; + ptr = lutil_strcopy( ptr, oid.bv_val ); + + if ( ctrls[ i ]->ldctl_iscritical ) { + ptr = lutil_strcopy( ptr, " criticality TRUE" ); + } + + if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { + int j; + + ptr = lutil_strcopy( ptr, " controlValue \"" ); + for ( j = 0; j < ctrls[ i ]->ldctl_value.bv_len; j++ ) + { + unsigned char o; + + o = ( ( ctrls[ i ]->ldctl_value.bv_val[ j ] >> 4 ) & 0xF ); + if ( o < 10 ) { + *ptr++ = '0' + o; + + } else { + *ptr++ = 'A' + o; + } + + o = ( ctrls[ i ]->ldctl_value.bv_val[ j ] & 0xF ); + if ( o < 10 ) { + *ptr++ = '0' + o; + + } else { + *ptr++ = 'A' + o; + } + } + + *ptr++ = '"'; + } + + *ptr++ = '}'; + *ptr = '\0'; + + ber_bvarray_add_x( valsp, &bv, memctx ); + ber_bvarray_add_x( nvalsp, &noid, memctx ); + } + + return rc; + +} + +static Entry *accesslog_entry( Operation *op, SlapReply *rs, int logop, Operation *op2 ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; log_info *li = on->on_bi.bi_private; @@ -915,13 +1212,40 @@ static Entry *accesslog_entry( Operation *op, int logop, rdn.bv_len = sprintf( rdn.bv_val, "%lu", op->o_connid ); attr_merge_one( e, ad_reqSession, &rdn, NULL ); - if ( BER_BVISNULL( &op->o_dn )) + if ( BER_BVISNULL( &op->o_dn ) ) { attr_merge_one( e, ad_reqAuthzID, (struct berval *)&slap_empty_bv, (struct berval *)&slap_empty_bv ); - else + } else { attr_merge_one( e, ad_reqAuthzID, &op->o_dn, &op->o_ndn ); + } /* FIXME: need to add reqControls and reqRespControls */ + if ( op->o_ctrls ) { + BerVarray vals = NULL, + nvals = NULL; + + if ( accesslog_ctrls( op->o_ctrls, &vals, &nvals, + op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) + { + attr_merge( e, ad_reqControls, vals, nvals ); + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + ber_bvarray_free_x( nvals, op->o_tmpmemctx ); + } + } + + if ( rs->sr_ctrls ) { + BerVarray vals = NULL, + nvals = NULL; + + if ( accesslog_ctrls( rs->sr_ctrls, &vals, &nvals, + op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) + { + attr_merge( e, ad_reqRespControls, vals, nvals ); + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + ber_bvarray_free_x( nvals, op->o_tmpmemctx ); + } + + } return e; } @@ -1007,7 +1331,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) { if ( li->li_success && rs->sr_err != LDAP_SUCCESS ) goto done; - e = accesslog_entry( op, logop, &op2 ); + e = accesslog_entry( op, rs, logop, &op2 ); attr_merge_one( e, ad_reqDN, &op->o_req_dn, &op->o_req_ndn ); @@ -1253,10 +1577,10 @@ static int accesslog_response(Operation *op, SlapReply *rs) { if ( op->orb_method == LDAP_AUTH_SIMPLE ) { attr_merge_one( e, ad_reqMethod, &simple, NULL ); } else { - bv.bv_len = STRLENOF("SASL()") + op->orb_tmp_mech.bv_len; + bv.bv_len = STRLENOF("SASL()") + op->orb_mech.bv_len; bv.bv_val = op->o_tmpalloc( bv.bv_len + 1, op->o_tmpmemctx ); ptr = lutil_strcopy( bv.bv_val, "SASL(" ); - ptr = lutil_strcopy( ptr, op->orb_tmp_mech.bv_val ); + ptr = lutil_strcopy( ptr, op->orb_mech.bv_val ); *ptr++ = ')'; *ptr = '\0'; attr_merge_one( e, ad_reqMethod, &bv, NULL ); @@ -1386,7 +1710,7 @@ accesslog_unbind( Operation *op, SlapReply *rs ) if ( !( li->li_ops & LOG_OP_UNBIND )) return SLAP_CB_CONTINUE; - e = accesslog_entry( op, LOG_EN_UNBIND, &op2 ); + e = accesslog_entry( op, rs, LOG_EN_UNBIND, &op2 ); op2.o_hdr = op->o_hdr; op2.o_tag = LDAP_REQ_ADD; op2.o_bd = li->li_db; @@ -1421,7 +1745,7 @@ accesslog_abandon( Operation *op, SlapReply *rs ) if ( !op->o_time || !( li->li_ops & LOG_OP_ABANDON )) return SLAP_CB_CONTINUE; - e = accesslog_entry( op, LOG_EN_ABANDON, &op2 ); + e = accesslog_entry( op, rs, LOG_EN_ABANDON, &op2 ); bv.bv_val = buf; bv.bv_len = sprintf( buf, "%d", op->orn_msgid ); attr_merge_one( e, ad_reqId, &bv, NULL ); @@ -1477,7 +1801,8 @@ static slap_overinst accesslog; static int accesslog_db_init( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -1491,7 +1816,8 @@ accesslog_db_init( static int accesslog_db_destroy( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -1522,12 +1848,13 @@ accesslog_db_root( Connection conn = {0}; OperationBuffer opbuf; - Operation *op = (Operation *) &opbuf; + Operation *op; Entry *e; int rc; - connection_fake_init( &conn, op, ctx ); + connection_fake_init( &conn, &opbuf, ctx ); + op = &opbuf.ob_op; op->o_bd = li->li_db; op->o_dn = li->li_db->be_rootdn; op->o_ndn = li->li_db->be_rootndn; @@ -1579,8 +1906,11 @@ accesslog_db_root( a = attr_find( e_ctx->e_attrs, slap_schema.si_ad_contextCSN ); if ( a ) { - attr_merge( e, slap_schema.si_ad_entryCSN, a->a_vals, NULL ); - attr_merge( e, a->a_desc, a->a_vals, NULL ); + /* FIXME: contextCSN could have multiple values! + * should select the one with the server's SID */ + attr_merge_one( e, slap_schema.si_ad_entryCSN, + &a->a_vals[0], &a->a_nvals[0] ); + attr_merge( e, a->a_desc, a->a_vals, a->a_nvals ); } be_entry_release_rw( op, e_ctx, 0 ); } @@ -1606,7 +1936,8 @@ accesslog_db_root( static int accesslog_db_open( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -1614,7 +1945,7 @@ accesslog_db_open( if ( !BER_BVISEMPTY( &li->li_db_suffix )) { - li->li_db = select_backend( &li->li_db_suffix, 0, 0 ); + li->li_db = select_backend( &li->li_db_suffix, 0 ); ch_free( li->li_db_suffix.bv_val ); BER_BVZERO( &li->li_db_suffix ); } @@ -1666,23 +1997,51 @@ int accesslog_initialize() if ( rc ) return rc; /* log schema integration */ + for ( i=0; lsyntaxes[i].oid; i++ ) { + int code; + + code = register_syntax( &lsyntaxes[ i ].syn ); + if ( code != 0 ) { + Debug( LDAP_DEBUG_ANY, + "accesslog_init: register_syntax failed\n", + 0, 0, 0 ); + return code; + } + + if ( lsyntaxes[i].mrs != NULL ) { + code = mr_make_syntax_compat_with_mrs( + lsyntaxes[i].oid, lsyntaxes[i].mrs ); + if ( code < 0 ) { + Debug( LDAP_DEBUG_ANY, + "accesslog_init: " + "mr_make_syntax_compat_with_mrs " + "failed\n", + 0, 0, 0 ); + return code; + } + } + } + for ( i=0; lattrs[i].at; i++ ) { int code; code = register_at( lattrs[i].at, lattrs[i].ad, 0 ); if ( code ) { Debug( LDAP_DEBUG_ANY, - "accesslog_init: register_at failed\n", 0, 0, 0 ); + "accesslog_init: register_at failed\n", + 0, 0, 0 ); return -1; } } + for ( i=0; locs[i].ot; i++ ) { int code; code = register_oc( locs[i].ot, locs[i].oc, 0 ); if ( code ) { Debug( LDAP_DEBUG_ANY, - "accesslog_init: register_oc failed\n", 0, 0, 0 ); + "accesslog_init: register_oc failed\n", + 0, 0, 0 ); return -1; } } diff --git a/servers/slapd/overlays/auditlog.c b/servers/slapd/overlays/auditlog.c index 601c733efd..8879ee39f4 100644 --- a/servers/slapd/overlays/auditlog.c +++ b/servers/slapd/overlays/auditlog.c @@ -184,7 +184,8 @@ static slap_overinst auditlog; static int auditlog_db_init( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -197,7 +198,8 @@ auditlog_db_init( static int auditlog_db_close( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; @@ -210,7 +212,8 @@ auditlog_db_close( static int auditlog_db_destroy( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; diff --git a/servers/slapd/overlays/collect.c b/servers/slapd/overlays/collect.c index 5fd2cb8325..d78f32b54a 100644 --- a/servers/slapd/overlays/collect.c +++ b/servers/slapd/overlays/collect.c @@ -29,7 +29,7 @@ #include #include "slap.h" - +#include "config.h" /* This is a cheap hack to implement a collective attribute. * @@ -46,6 +46,124 @@ typedef struct collect_info { AttributeDescription *ci_ad; } collect_info; +static int +collect_cf( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + int rc = 1; + + switch( c->op ) { + case SLAP_CONFIG_EMIT: + { + collect_info *ci; + for ( ci = on->on_bi.bi_private; ci; ci = ci->ci_next ) { + struct berval bv; + + bv.bv_len = ci->ci_dn.bv_len + 3 + + ci->ci_ad->ad_cname.bv_len; + bv.bv_val = ch_malloc( bv.bv_len + 1 ); + sprintf( bv.bv_val, "\"%s\" %s", ci->ci_dn.bv_val, + ci->ci_ad->ad_cname.bv_val ); + ber_bvarray_add( &c->rvalue_vals, &bv ); + rc = 0; + } + } + break; + case LDAP_MOD_DELETE: + if ( c->valx == -1 ) { + /* Delete entire attribute */ + collect_info *ci; + while (( ci = on->on_bi.bi_private )) { + on->on_bi.bi_private = ci->ci_next; + ch_free( ci->ci_dn.bv_val ); + ch_free( ci ); + } + } else { + /* Delete just one value */ + collect_info **cip, *ci; + int i; + cip = (collect_info **)&on->on_bi.bi_private; + for ( i=0; i <= c->valx; i++, cip = &ci->ci_next ) ci = *cip; + *cip = ci->ci_next; + ch_free( ci->ci_dn.bv_val ); + ch_free( ci ); + } + rc = 0; + break; + case SLAP_CONFIG_ADD: + case LDAP_MOD_ADD: + { + collect_info *ci; + struct berval bv, dn; + const char *text; + AttributeDescription *ad = NULL; + + ber_str2bv( c->argv[1], 0, 0, &bv ); + if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: \"%s\"", + c->argv[0], c->argv[1] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ARG_BAD_CONF; + } + if ( slap_str2ad( c->argv[2], &ad, &text ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"", + c->argv[0], c->argv[2] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ARG_BAD_CONF; + } + + /* The on->on_bi.bi_private pointer can be used for + * anything this instance of the overlay needs. + */ + ci = ch_malloc( sizeof( collect_info )); + ci->ci_ad = ad; + ci->ci_dn = dn; + ci->ci_next = on->on_bi.bi_private; + on->on_bi.bi_private = ci; + rc = 0; + } + } + return rc; +} + +static ConfigTable collectcfg[] = { + { "collectinfo", "dn> bd_info; + collect_info *ci; + + while (( ci = on->on_bi.bi_private )) { + on->on_bi.bi_private = ci->ci_next; + ch_free( ci->ci_dn.bv_val ); + ch_free( ci ); + } + return 0; +} + static int collect_response( Operation *op, SlapReply *rs ) { @@ -56,7 +174,6 @@ collect_response( Operation *op, SlapReply *rs ) * a search entry */ if ( ci && rs->sr_type == REP_SEARCH ) { - Entry *new = NULL; int rc; op->o_bd->bd_info = (BackendInfo *)on->on_info; @@ -65,9 +182,8 @@ collect_response( Operation *op, SlapReply *rs ) BerVarray vals = NULL; /* Is our configured entry an ancestor of this one? */ - rc = rs->sr_entry->e_nname.bv_len - ci->ci_dn.bv_len; - if ( rc < 1 || strcmp( rs->sr_entry->e_nname.bv_val + rc, - ci->ci_dn.bv_val )) continue; + if ( !dnIsSuffix( &rs->sr_entry->e_nname, &ci->ci_dn )) + continue; /* Extract the values of the desired attribute from * the ancestor entry @@ -82,82 +198,33 @@ collect_response( Operation *op, SlapReply *rs ) * don't modify it directly. Make a copy and * work with that instead. */ - if ( !new ) { - new = entry_dup( rs->sr_entry ); + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { + rs->sr_entry = entry_dup( rs->sr_entry ); + rs->sr_flags |= REP_ENTRY_MODIFIABLE | + REP_ENTRY_MUSTBEFREED; } - attr_merge( new, ci->ci_ad, vals, NULL ); + attr_merge( rs->sr_entry, ci->ci_ad, vals, NULL ); ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } - - if ( new ) { - rs->sr_entry = new; - rs->sr_flags |= REP_ENTRY_MUSTBEFREED; - } } /* Default is to just fall through to the normal processing */ return SLAP_CB_CONTINUE; } -static int collect_config( - BackendDB *be, - const char *fname, - int lineno, - int argc, - char **argv -) -{ - slap_overinst *on = (slap_overinst *) be->bd_info; - AttributeDescription *ad = NULL; - - /* The config syntax is "collectinfo " - * and only one directive may be specified per overlay instance. - */ - - if ( strcasecmp( argv[0], "collectinfo" ) == 0 ) { - collect_info *ci; - struct berval bv, dn; - const char *text; - if ( argc != 3 ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: argument missing in \"collectinfo \" line.\n", - fname, lineno, 0 ); - return( 1 ); - } - ber_str2bv( argv[1], 0, 0, &bv ); - if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL ) ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: invalid DN in \"collectinfo\" line: %s.\n", - fname, lineno, text ); - return( 1 ); - } - if ( slap_str2ad( argv[2], &ad, &text ) ) { - Debug( LDAP_DEBUG_ANY, - "%s: line %d: attribute description unknown in \"collectinfo\" line: %s.\n", - fname, lineno, text ); - return( 1 ); - } - - /* The on->on_bi.bi_private pointer can be used for - * anything this instance of the overlay needs. - */ - ci = ch_malloc( sizeof( collect_info )); - ci->ci_ad = ad; - ci->ci_dn = dn; - ci->ci_next = on->on_bi.bi_private; - on->on_bi.bi_private = ci; - return 0; - } - return SLAP_CONF_UNKNOWN; -} - static slap_overinst collect; int collect_initialize() { + int code; + collect.on_bi.bi_type = "collect"; - collect.on_bi.bi_db_config = collect_config; + collect.on_bi.bi_db_destroy = collect_destroy; collect.on_response = collect_response; + collect.on_bi.bi_cf_ocs = collectocs; + code = config_register_schema( collectcfg, collectocs ); + if ( code ) return code; + return overlay_register( &collect ); } diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c index c86c11a53a..aed82a6620 100644 --- a/servers/slapd/overlays/constraint.c +++ b/servers/slapd/overlays/constraint.c @@ -168,10 +168,10 @@ constraint_cf_gen( ConfigArgs *c ) switch (c->type) { case CONSTRAINT_ATTRIBUTE: if ( slap_str2ad( c->argv[1], &ap.ap, &text ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s <%s>: %s\n", c->argv[0], c->argv[1], text ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s: %s\n", c->log, c->msg, 0 ); + "%s: %s\n", c->log, c->cr_msg, 0 ); return( ARG_BAD_CONF ); } @@ -185,21 +185,21 @@ constraint_cf_gen( ConfigArgs *c ) regerror( err, ap.re, errmsg, sizeof(errmsg) ); ch_free(ap.re); - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s %s: Illegal regular expression \"%s\": Error %s", c->argv[0], c->argv[1], c->argv[3], errmsg); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s: %s\n", c->log, c->msg, 0 ); + "%s: %s\n", c->log, c->cr_msg, 0 ); ap.re = NULL; return( ARG_BAD_CONF ); } ap.re_str = ch_strdup( c->argv[3] ); } else { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s %s: Unknown constraint type: %s", c->argv[0], c->argv[1], c->argv[2] ); Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, - "%s: %s\n", c->log, c->msg, 0 ); + "%s: %s\n", c->log, c->cr_msg, 0 ); return ( ARG_BAD_CONF ); } @@ -237,14 +237,14 @@ constraint_violation( constraint *c, struct berval *bv ) } static char * -print_message( const char *fmt, AttributeDescription *a ) +print_message( const char *errtext, AttributeDescription *a ) { char *ret; int sz; - sz = strlen(fmt) + a->ad_cname.bv_len + 1; + sz = strlen(errtext) + sizeof(" on ") + a->ad_cname.bv_len; ret = ch_malloc(sz); - snprintf( ret, sz, fmt, a->ad_cname.bv_val ); + snprintf( ret, sz, "%s on %s", errtext, a->ad_cname.bv_val ); return ret; } @@ -256,7 +256,7 @@ constraint_add( Operation *op, SlapReply *rs ) constraint *c = on->on_bi.bi_private, *cp; BerVarray b = NULL; int i; - const char *rsv = "add breaks regular expression constraint on %s"; + const char *rsv = "add breaks regular expression constraint"; char *msg; if ((a = op->ora_e->e_attrs) == NULL) { @@ -301,7 +301,7 @@ constraint_modify( Operation *op, SlapReply *rs ) Modifications *m; BerVarray b = NULL; int i; - const char *rsv = "modify breaks regular expression constraint on %s"; + const char *rsv = "modify breaks regular expression constraint"; char *msg; if ((m = op->orm_modlist) == NULL) { @@ -343,8 +343,8 @@ constraint_modify( Operation *op, SlapReply *rs ) static int constraint_close( - BackendDB *be - ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; constraint *ap, *a2; diff --git a/servers/slapd/overlays/dds.c b/servers/slapd/overlays/dds.c index 80999f6381..278658eb58 100644 --- a/servers/slapd/overlays/dds.c +++ b/servers/slapd/overlays/dds.c @@ -123,7 +123,7 @@ dds_expire( void *ctx, dds_info_t *di ) Connection conn = { 0 }; OperationBuffer opbuf; Operation *op; - slap_callback sc = { 0 }, sc2 = { 0 }; + slap_callback sc = { 0 }; dds_cb_t dc = { 0 }; dds_expire_t *de = NULL, **dep; SlapReply rs = { REP_RESULT }; @@ -134,13 +134,13 @@ dds_expire( void *ctx, dds_info_t *di ) int ndeletes, ntotdeletes; - op = (Operation *)&opbuf; - connection_fake_init( &conn, op, ctx ); + connection_fake_init( &conn, &opbuf, ctx ); + op = &opbuf.ob_op; op->o_tag = LDAP_REQ_SEARCH; memset( &op->oq_search, 0, sizeof( op->oq_search ) ); - op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0, 0 ); + op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0 ); op->o_req_dn = op->o_bd->be_suffix[ 0 ]; op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ]; @@ -193,10 +193,8 @@ done_search:; op->o_tag = LDAP_REQ_DELETE; op->o_callback = ≻ - sc.sc_response = slap_replog_cb; + sc.sc_response = slap_null_cb; sc.sc_private = NULL; - sc.sc_next = &sc2; - sc2.sc_response = slap_null_cb; for ( ntotdeletes = 0, ndeletes = 1; dc.dc_ndnlist != NULL && ndeletes > 0; ) { ndeletes = 0; @@ -950,7 +948,7 @@ slap_parse_refresh( tag = ber_peek_tag( ber, &len ); - if ( len != 0 ) { + if ( tag != LBER_DEFAULT || len != 0 ) { decoding_error:; Log1( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR, "slap_parse_refresh: decoding error, len=%ld\n", @@ -989,7 +987,6 @@ dds_op_extended( Operation *op, SlapReply *rs ) SlapReply rs2 = { REP_RESULT }; Operation op2 = *op; slap_callback sc = { 0 }; - slap_callback sc2 = { 0 }; Modifications ttlmod = { { 0 } }; struct berval ttlvalues[ 2 ]; char ttlbuf[] = "31557600"; @@ -1082,9 +1079,7 @@ dds_op_extended( Operation *op, SlapReply *rs ) op2.o_bd = &db; db.bd_info = (BackendInfo *)on->on_info; op2.o_callback = ≻ - sc.sc_response = slap_replog_cb; - sc.sc_next = &sc2; - sc2.sc_response = slap_null_cb; + sc.sc_response = slap_null_cb; op2.o_relax = SLAP_CONTROL_CRITICAL; op2.orm_modlist = &ttlmod; @@ -1368,20 +1363,20 @@ dds_cfgen( ConfigArgs *c ) case DDS_MAXTTL: if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "DDS unable to parse dds-max-ttl \"%s\"", c->argv[ 1 ] ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-max-ttl=%ld; must be between %d and %d", t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } @@ -1390,20 +1385,20 @@ dds_cfgen( ConfigArgs *c ) case DDS_MINTTL: if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "DDS unable to parse dds-min-ttl \"%s\"", c->argv[ 1 ] ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-min-ttl=%ld", t ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } @@ -1417,20 +1412,20 @@ dds_cfgen( ConfigArgs *c ) case DDS_DEFAULTTTL: if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "DDS unable to parse dds-default-ttl \"%s\"", c->argv[ 1 ] ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-default-ttl=%ld", t ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } @@ -1444,20 +1439,20 @@ dds_cfgen( ConfigArgs *c ) case DDS_INTERVAL: if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "DDS unable to parse dds-interval \"%s\"", c->argv[ 1 ] ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } if ( t <= 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-interval=%ld", t ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } @@ -1481,20 +1476,20 @@ dds_cfgen( ConfigArgs *c ) case DDS_TOLERANCE: if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) { - snprintf( c->msg, sizeof( c->msg), + snprintf( c->cr_msg, sizeof( c->cr_msg), "DDS unable to parse dds-tolerance \"%s\"", c->argv[ 1 ] ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } if ( t < 0 || t > DDS_RF2589_MAX_TTL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-tolerance=%ld", t ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } @@ -1503,10 +1498,10 @@ dds_cfgen( ConfigArgs *c ) case DDS_MAXDYNAMICOBJS: if ( c->value_int < 0 ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "DDS invalid dds-max-dynamicObjects=%d", c->value_int ); Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, - "%s: %s.\n", c->log, c->msg ); + "%s: %s.\n", c->log, c->cr_msg ); return 1; } di->di_max_dynamicObjects = c->value_int; @@ -1522,7 +1517,8 @@ dds_cfgen( ConfigArgs *c ) static int dds_db_init( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr) { slap_overinst *on = (slap_overinst *)be->bd_info; dds_info_t *di; @@ -1611,8 +1607,8 @@ dds_count( void *ctx, BackendDB *be ) slap_callback sc = { 0 }; SlapReply rs = { REP_RESULT }; - op = (Operation *)&opbuf; - connection_fake_init( &conn, op, ctx ); + connection_fake_init( &conn, &opbuf, ctx ); + op = &opbuf.ob_op; op->o_tag = LDAP_REQ_SEARCH; memset( &op->oq_search, 0, sizeof( op->oq_search ) ); @@ -1671,7 +1667,8 @@ done_search:; static int dds_db_open( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; dds_info_t *di = on->on_bi.bi_private; @@ -1736,7 +1733,8 @@ done:; static int dds_db_close( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; dds_info_t *di = on->on_bi.bi_private; @@ -1758,7 +1756,8 @@ dds_db_close( static int dds_db_destroy( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *)be->bd_info; dds_info_t *di = on->on_bi.bi_private; @@ -1790,7 +1789,7 @@ slap_exop_refresh( op->o_log_prefix, op->o_req_ndn.bv_val ); op->o_req_dn = op->o_req_ndn; - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); + op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( !SLAP_DYNAMIC( op->o_bd ) ) { send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "backend does not support dynamic directory services" ); diff --git a/servers/slapd/overlays/dyngroup.c b/servers/slapd/overlays/dyngroup.c index 6b28ecc8c5..fdc8d70d9b 100644 --- a/servers/slapd/overlays/dyngroup.c +++ b/servers/slapd/overlays/dyngroup.c @@ -28,7 +28,9 @@ #include #include +#include "lutil.h" #include "slap.h" +#include "config.h" /* This overlay extends the Compare operation to detect members of a * dynamic group. It has no effect on any other operations. It must @@ -43,6 +45,100 @@ typedef struct adpair { AttributeDescription *ap_uri; } adpair; +static int dgroup_cf( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + int rc = 1; + + switch( c->op ) { + case SLAP_CONFIG_EMIT: + { + adpair *ap; + for ( ap = on->on_bi.bi_private; ap; ap = ap->ap_next ) { + struct berval bv; + char *ptr; + bv.bv_len = ap->ap_mem->ad_cname.bv_len + 1 + + ap->ap_uri->ad_cname.bv_len; + bv.bv_val = ch_malloc( bv.bv_len + 1 ); + ptr = lutil_strcopy( bv.bv_val, ap->ap_mem->ad_cname.bv_val ); + *ptr++ = ' '; + strcpy( ptr, ap->ap_uri->ad_cname.bv_val ); + ber_bvarray_add( &c->rvalue_vals, &bv ); + rc = 0; + } + } + break; + case LDAP_MOD_DELETE: + if ( c->valx == -1 ) { + adpair *ap; + while (( ap = on->on_bi.bi_private )) { + on->on_bi.bi_private = ap->ap_next; + ch_free( ap ); + } + } else { + adpair **app, *ap; + int i; + app = (adpair **)&on->on_bi.bi_private; + for (i=0; i<=c->valx; i++, app = &ap->ap_next) { + ap = *app; + } + *app = ap->ap_next; + ch_free( ap ); + } + rc = 0; + break; + case SLAP_CONFIG_ADD: + case LDAP_MOD_ADD: + { + adpair ap = { NULL, NULL, NULL }, *a2; + const char *text; + if ( slap_str2ad( c->argv[1], &ap.ap_mem, &text ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"", + c->argv[0], c->argv[1] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ARG_BAD_CONF; + } + if ( slap_str2ad( c->argv[2], &ap.ap_uri, &text ) ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s attribute description unknown: \"%s\"", + c->argv[0], c->argv[2] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg, 0 ); + return ARG_BAD_CONF; + } + /* The on->on_bi.bi_private pointer can be used for + * anything this instance of the overlay needs. + */ + a2 = ch_malloc( sizeof(adpair) ); + a2->ap_next = on->on_bi.bi_private; + a2->ap_mem = ap.ap_mem; + a2->ap_uri = ap.ap_uri; + on->on_bi.bi_private = a2; + rc = 0; + } + } + return rc; +} + +static ConfigTable dgroupcfg[] = { + { "attrpair", "member-attribute> bd_info; - adpair ap = { NULL, NULL, NULL }, *a2; - - if ( strcasecmp( argv[0], "attrpair" ) == 0 ) { - const char *text; - if ( argc != 3 ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "attribute description missing in " - "\"attrpair \" line.\n", - fname, lineno, 0 ); - return( 1 ); - } - if ( slap_str2ad( argv[1], &ap.ap_mem, &text ) ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "attribute description unknown \"attrpair\" line: %s.\n", - fname, lineno, text ); - return( 1 ); - } - if ( slap_str2ad( argv[2], &ap.ap_uri, &text ) ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "attribute description unknown \"attrpair\" line: %s.\n", - fname, lineno, text ); - return( 1 ); - } - /* The on->on_bi.bi_private pointer can be used for - * anything this instance of the overlay needs. - */ - - a2 = ch_malloc( sizeof(adpair) ); - a2->ap_next = on->on_bi.bi_private; - a2->ap_mem = ap.ap_mem; - a2->ap_uri = ap.ap_uri; - on->on_bi.bi_private = a2; - } else { - return SLAP_CONF_UNKNOWN; - } - return 0; -} - static int dyngroup_close( - BackendDB *be + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; @@ -154,11 +204,16 @@ static slap_overinst dyngroup; */ int dyngroup_initialize() { + int code; + dyngroup.on_bi.bi_type = "dyngroup"; - dyngroup.on_bi.bi_db_config = dyngroup_config; dyngroup.on_bi.bi_db_close = dyngroup_close; dyngroup.on_response = dyngroup_response; + dyngroup.on_bi.bi_cf_ocs = dgroupocs; + code = config_register_schema( dgroupcfg, dgroupocs ); + if ( code ) return code; + return overlay_register( &dyngroup ); } diff --git a/servers/slapd/overlays/dynlist.c b/servers/slapd/overlays/dynlist.c index ff2d80b6e7..50119eb7a1 100644 --- a/servers/slapd/overlays/dynlist.c +++ b/servers/slapd/overlays/dynlist.c @@ -58,6 +58,8 @@ static AttributeName anlist_no_attrs[] = { static AttributeName *slap_anlist_no_attrs = anlist_no_attrs; #endif +static AttributeDescription *ad_dgIdentity; + typedef struct dynlist_info_t { ObjectClass *dli_oc; AttributeDescription *dli_ad; @@ -67,13 +69,20 @@ typedef struct dynlist_info_t { } dynlist_info_t; static dynlist_info_t * -dynlist_is_dynlist( Operation *op, SlapReply *rs ) +dynlist_is_dynlist_next( Operation *op, SlapReply *rs, dynlist_info_t *old_dli ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; + dynlist_info_t *dli; Attribute *a; + if ( old_dli == NULL ) { + dli = (dynlist_info_t *)on->on_bi.bi_private; + + } else { + dli = old_dli->dli_next; + } + a = attrs_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass ); if ( a == NULL ) { /* FIXME: objectClass must be present; for non-storage @@ -306,9 +315,9 @@ done:; } static int -dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) +dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) { - Attribute *a; + Attribute *a, *id = NULL; slap_callback cb; Operation o = *op; SlapReply r = { REP_SEARCH }; @@ -325,9 +334,19 @@ dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) return SLAP_CB_CONTINUE; } - e = entry_dup( rs->sr_entry ); + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) { + e = entry_dup( rs->sr_entry ); + } else { + e = rs->sr_entry; + } e_flags = rs->sr_flags | ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED ); + if ( ad_dgIdentity && ( id = attrs_find( e->e_attrs, ad_dgIdentity ))) { + o.o_dn = id->a_vals[0]; + o.o_ndn = id->a_nvals[0]; + o.o_groups = NULL; + } + dlc.dlc_e = e; dlc.dlc_dli = dli; cb.sc_private = &dlc; @@ -368,7 +387,7 @@ dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) if ( lud->lud_host != NULL ) { /* FIXME: host not allowed; reject as illegal? */ - Debug( LDAP_DEBUG_ANY, "dynlist_send_entry(\"%s\"): " + Debug( LDAP_DEBUG_ANY, "dynlist_prepare_entry(\"%s\"): " "illegal URI \"%s\"\n", e->e_name.bv_val, url->bv_val, 0 ); goto cleanup; @@ -466,7 +485,7 @@ dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) goto cleanup; } - o.o_bd = select_backend( &o.o_req_ndn, 0, 1 ); + o.o_bd = select_backend( &o.o_req_ndn, 1 ); if ( o.o_bd && o.o_bd->be_search ) { #ifdef SLAP_OPATTRS r.sr_attr_flags = slap_attr_flags( o.ors_attrs ); @@ -475,6 +494,9 @@ dynlist_send_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) } cleanup:; + if ( id ) { + slap_op_groups_free( &o ); + } if ( o.ors_filter ) { filter_free_x( &o, o.ors_filter ); } @@ -489,7 +511,8 @@ cleanup:; if ( !BER_BVISNULL( &o.o_req_ndn ) ) { op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx ); } - assert( o.ors_filterstr.bv_val != lud->lud_filter ); + assert( BER_BVISNULL( &o.ors_filterstr ) + || o.ors_filterstr.bv_val != lud->lud_filter ); op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx ); ldap_free_urldesc( lud ); } @@ -519,6 +542,8 @@ dynlist_compare( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; + Operation o = *op; + Entry *e; for ( ; dli != NULL; dli = dli->dli_next ) { if ( op->oq_compare.rs_ava->aa_desc == dli->dli_member_ad ) { @@ -526,12 +551,18 @@ dynlist_compare( Operation *op, SlapReply *rs ) * interested in. We'll use slapd's existing dyngroup * evaluator to get the answer we want. */ - int cache = op->o_do_not_cache; - - op->o_do_not_cache = 1; - rs->sr_err = backend_group( op, NULL, &op->o_req_ndn, - &op->oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad ); - op->o_do_not_cache = cache; + struct berval *id = NULL; + + o.o_do_not_cache = 1; + + if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn, + ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS ) { + o.o_dn = *id; + o.o_ndn = *id; + o.o_groups = NULL; /* authz changed, invalidate cached groups */ + } + rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn, + &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad ); switch ( rs->sr_err ) { case LDAP_SUCCESS: rs->sr_err = LDAP_COMPARE_TRUE; @@ -549,45 +580,35 @@ dynlist_compare( Operation *op, SlapReply *rs ) break; } + if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx ); + return SLAP_CB_CONTINUE; } } + if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) != + LDAP_SUCCESS || e == NULL ) { + return SLAP_CB_CONTINUE; + } + if ( ad_dgIdentity ) { + Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity ); + if ( id ) { + o.o_dn = id->a_vals[0]; + o.o_ndn = id->a_nvals[0]; + o.o_groups = NULL; + } + } dli = (dynlist_info_t *)on->on_bi.bi_private; for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) { Attribute *a; slap_callback cb; - Operation o = *op; SlapReply r = { REP_SEARCH }; AttributeName an[2]; int rc; dynlist_sc_t dlc = { 0 }; - Entry *e; - - int cache = op->o_do_not_cache; - struct berval op_dn = op->o_dn, - op_ndn = op->o_ndn; - BackendDB *op_bd = op->o_bd; - - /* fetch the entry as rootdn (a hack to see if it exists - * and if it has the right objectClass) */ - op->o_do_not_cache = 1; - op->o_dn = op->o_bd->be_rootdn; - op->o_ndn = op->o_bd->be_rootndn; - op->o_bd = select_backend( &op->o_req_ndn, 0, 0 ); - - r.sr_err = be_entry_get_rw( op, &op->o_req_ndn, - dli->dli_oc, NULL, 0, &e ); - if ( e != NULL ) { - be_entry_release_r( op, e ); - } - op->o_do_not_cache = cache; - op->o_dn = op_dn; - op->o_ndn = op_ndn; - op->o_bd = op_bd; - if ( r.sr_err != LDAP_SUCCESS ) { + + if ( !is_entry_objectclass_or_sub( e, dli->dli_oc )) continue; - } /* if the entry has the right objectClass, generate * the dynamic list and compare */ @@ -603,7 +624,7 @@ dynlist_compare( Operation *op, SlapReply *rs ) o.ors_tlimit = SLAP_NO_LIMIT; o.ors_slimit = SLAP_NO_LIMIT; - o.o_bd = select_backend( &o.o_req_ndn, 0, 1 ); + o.o_bd = select_backend( &o.o_req_ndn, 1 ); if ( !o.o_bd || !o.o_bd->be_search ) { return SLAP_CB_CONTINUE; } @@ -628,6 +649,10 @@ dynlist_compare( Operation *op, SlapReply *rs ) rc = o.o_bd->be_search( &o, &r ); filter_free_x( &o, o.ors_filter ); + if ( o.o_dn.bv_val != op->o_dn.bv_val ) { + slap_op_groups_free( &o ); + } + if ( rc != 0 ) { return rc; } @@ -675,9 +700,17 @@ dynlist_response( Operation *op, SlapReply *rs ) case LDAP_REQ_SEARCH: if ( rs->sr_type == REP_SEARCH && !get_manageDSAit( op ) ) { - dli = dynlist_is_dynlist( op, rs ); - if ( dli != NULL ) { - return dynlist_send_entry( op, rs, dli ); + int rc = LDAP_OTHER; + + for ( dli = dynlist_is_dynlist_next( op, rs, NULL ); + dli; + dli = dynlist_is_dynlist_next( op, rs, dli ) ) + { + rc = dynlist_prepare_entry( op, rs, dli ); + } + + if ( rc != LDAP_OTHER ) { + return rc; } } break; @@ -797,31 +830,17 @@ dynlist_db_config( for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; *dlip; dlip = &(*dlip)->dli_next ) { - /* The check on objectClass may be relaxed */ -#if 0 - if ( (*dlip)->dli_oc == oc ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "\"dynlist-attrset []\": " - "objectClass \"%s\" already mapped.\n", - fname, lineno, oc->soc_cname.bv_val ); - return 1; - } -#endif - - if ( (*dlip)->dli_ad == ad ) { + /* The same URL attribute / member attribute pair + * cannot be repeated */ + if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: " "\"dynlist-attrset []\": " "URL attributeDescription \"%s\" already mapped.\n", fname, lineno, ad->ad_cname.bv_val ); +#if 0 + /* make it a warning... */ return 1; - } - - if ( member_ad != NULL && (*dlip)->dli_member_ad == member_ad ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "\"dynlist-attrset []\": " - "member attributeDescription \"%s\" already mapped.\n", - fname, lineno, member_ad->ad_cname.bv_val ); - return 1; +#endif } } @@ -888,35 +907,20 @@ dynlist_db_config( return 1; } - for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; *dlip; dlip = &(*dlip)->dli_next ) { -#if 0 - /* The check on objectClass may be relaxed */ - if ( (*dlip)->dli_oc == oc ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "\"dynlist-attrpair \": " - "objectClass \"%s\" already mapped.\n", - fname, lineno, oc->soc_cname.bv_val ); - return 1; - } -#endif - - if ( (*dlip)->dli_ad == ad ) { + /* The same URL attribute / member attribute pair + * cannot be repeated */ + if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: " "\"dynlist-attrpair \": " "URL attributeDescription \"%s\" already mapped.\n", fname, lineno, ad->ad_cname.bv_val ); +#if 0 + /* make it a warning... */ return 1; - } - - if ( member_ad != NULL && (*dlip)->dli_member_ad == member_ad ) { - Debug( LDAP_DEBUG_ANY, "%s: line %d: " - "\"dynlist-attrpair \": " - "member attributeDescription \"%s\" already mapped.\n", - fname, lineno, member_ad->ad_cname.bv_val ); - return 1; +#endif } } @@ -991,12 +995,12 @@ dl_cfgen( ConfigArgs *c ) case DL_ATTRSET: for ( i = 0; dli; i++, dli = dli->dli_next ) { struct berval bv; - char *ptr = c->msg; + char *ptr = c->cr_msg; assert( dli->dli_oc != NULL ); assert( dli->dli_ad != NULL ); - ptr += snprintf( c->msg, sizeof( c->msg ), + ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ), SLAP_X_ORDERED_FMT "%s %s", i, dli->dli_oc->soc_cname.bv_val, dli->dli_ad->ad_cname.bv_val ); @@ -1007,7 +1011,7 @@ dl_cfgen( ConfigArgs *c ) ptr = lutil_strcopy( ptr, dli->dli_member_ad->ad_cname.bv_val ); } - bv.bv_val = c->msg; + bv.bv_val = c->cr_msg; bv.bv_len = ptr - bv.bv_val; value_add_one( &c->rvalue_vals, &bv ); } @@ -1071,7 +1075,7 @@ dl_cfgen( ConfigArgs *c ) break; } - return 1; /* FIXME */ + return rc; } switch( c->type ) { @@ -1085,46 +1089,46 @@ dl_cfgen( ConfigArgs *c ) oc = oc_find( c->argv[ 1 ] ); if ( oc == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "unable to find ObjectClass \"%s\"", c->argv[ 1 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } rc = slap_str2ad( c->argv[ 2 ], &ad, &text ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "unable to find AttributeDescription \"%s\"", c->argv[ 2 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "AttributeDescription \"%s\" " "must be a subtype of \"labeledURI\"", c->argv[ 2 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } if ( c->argc == 4 ) { rc = slap_str2ad( c->argv[ 3 ], &member_ad, &text ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "unable to find AttributeDescription \"%s\"\n", c->argv[ 3 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } } @@ -1132,37 +1136,19 @@ dl_cfgen( ConfigArgs *c ) for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; *dlip; dlip = &(*dlip)->dli_next ) { - /* The check on objectClass may be relaxed */ -#if 0 - if ( (*dlip)->dli_oc == oc ) { - snprintf( c->msg, sizeof( c->msg ), - "\"dynlist-attrset []\": " - "objectClass \"%s\" already mapped.\n", - oc->soc_cname.bv_val ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); - return 1; - } -#endif - - if ( (*dlip)->dli_ad == ad ) { - snprintf( c->msg, sizeof( c->msg ), + /* The same URL attribute / member attribute pair + * cannot be repeated */ + if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "URL attributeDescription \"%s\" already mapped.\n", ad->ad_cname.bv_val ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); - return 1; - } - - if ( member_ad != NULL && (*dlip)->dli_member_ad == member_ad ) { - snprintf( c->msg, sizeof( c->msg ), - "\"dynlist-attrset []\": " - "member attributeDescription \"%s\" already mapped.\n", - member_ad->ad_cname.bv_val ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); +#if 0 + /* make it a warning... */ return 1; +#endif } } @@ -1173,12 +1159,12 @@ dl_cfgen( ConfigArgs *c ) i < c->valx; i++ ) { if ( *dlip == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "invalid index {%d}\n", c->valx ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } dlip = &(*dlip)->dli_next; @@ -1203,10 +1189,10 @@ dl_cfgen( ConfigArgs *c ) } break; case DL_ATTRPAIR_COMPAT: - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "warning: \"attrpair\" only supported for limited " "backward compatibility with overlay \"dyngroup\"" ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 ); /* fallthru */ case DL_ATTRPAIR: { @@ -1218,81 +1204,63 @@ dl_cfgen( ConfigArgs *c ) oc = oc_find( "groupOfURLs" ); if ( oc == NULL ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrpair \": " "unable to find default ObjectClass \"groupOfURLs\"" ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } rc = slap_str2ad( c->argv[ 1 ], &member_ad, &text ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrpair \": " "unable to find AttributeDescription \"%s\"", c->argv[ 1 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } rc = slap_str2ad( c->argv[ 2 ], &ad, &text ); if ( rc != LDAP_SUCCESS ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrpair \": " "unable to find AttributeDescription \"%s\"\n", c->argv[ 2 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } if ( !is_at_subtype( ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) { - snprintf( c->msg, sizeof( c->msg ), + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrset []\": " "AttributeDescription \"%s\" " "must be a subtype of \"labeledURI\"", c->argv[ 2 ] ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); return 1; } for ( dlip = (dynlist_info_t **)&on->on_bi.bi_private; *dlip; dlip = &(*dlip)->dli_next ) { - /* The check on objectClass may be relaxed */ -#if 0 - if ( (*dlip)->dli_oc == oc ) { - snprintf( c->msg, sizeof( c->msg ), - "\"dynlist-attrpair \": " - "objectClass \"%s\" already mapped.\n", - oc->soc_cname.bv_val ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); - return 1; - } -#endif - - if ( (*dlip)->dli_ad == ad ) { - snprintf( c->msg, sizeof( c->msg ), + /* The same URL attribute / member attribute pair + * cannot be repeated */ + if ( (*dlip)->dli_ad == ad && (*dlip)->dli_member_ad == member_ad ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "\"dynlist-attrpair \": " "URL attributeDescription \"%s\" already mapped.\n", ad->ad_cname.bv_val ); Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); - return 1; - } - - if ( member_ad != NULL && (*dlip)->dli_member_ad == member_ad ) { - snprintf( c->msg, sizeof( c->msg ), - "\"dynlist-attrpair \": " - "member attributeDescription \"%s\" already mapped.\n", - member_ad->ad_cname.bv_val ); - Debug( LDAP_DEBUG_ANY, "%s: %s.\n", - c->log, c->msg, 0 ); + c->log, c->cr_msg, 0 ); +#if 0 + /* make it a warning... */ return 1; +#endif } } @@ -1317,12 +1285,15 @@ dl_cfgen( ConfigArgs *c ) static int dynlist_db_open( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; dynlist_info_t *dli = (dynlist_info_t *)on->on_bi.bi_private; ObjectClass *oc = NULL; AttributeDescription *ad = NULL; + const char *text; + int rc; if ( dli == NULL ) { dli = ch_calloc( 1, sizeof( dynlist_info_t ) ); @@ -1330,16 +1301,12 @@ dynlist_db_open( } for ( ; dli; dli = dli->dli_next ) { - const char *text; - int rc; - if ( dli->dli_oc == NULL ) { if ( oc == NULL ) { oc = oc_find( "groupOfURLs" ); if ( oc == NULL ) { - Debug( LDAP_DEBUG_ANY, "dynlist_db_open: " - "unable to fetch objectClass \"groupOfURLs\".\n", - 0, 0, 0 ); + sprintf( cr->msg, "unable to fetch objectClass \"groupOfURLs\"" ); + Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 ); return 1; } } @@ -1351,9 +1318,9 @@ dynlist_db_open( if ( ad == NULL ) { rc = slap_str2ad( "memberURL", &ad, &text ); if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_ANY, "dynlist_db_open: " - "unable to fetch attributeDescription \"memberURL\": %d (%s).\n", - rc, text, 0 ); + sprintf( cr->msg, "unable to fetch attributeDescription \"memberURL\": %d (%s)", + rc, text ); + Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s.\n", cr->msg, 0, 0 ); return 1; } } @@ -1369,12 +1336,21 @@ dynlist_db_open( } } + rc = slap_str2ad( "dgIdentity", &ad_dgIdentity, &text ); + if ( rc != LDAP_SUCCESS ) { + sprintf( cr->msg, "unable to fetch attributeDescription \"dgIdentity\": %d (%s)", + rc, text ); + Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 ); + /* Just a warning */ + } + return 0; } static int dynlist_db_destroy( - BackendDB *be ) + BackendDB *be, + ConfigReply *cr ) { slap_overinst *on = (slap_overinst *) be->bd_info; diff --git a/servers/slapd/overlays/memberof.c b/servers/slapd/overlays/memberof.c new file mode 100644 index 0000000000..8e282e9991 --- /dev/null +++ b/servers/slapd/overlays/memberof.c @@ -0,0 +1,1947 @@ +/* memberof.c - back-reference for group membership */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2005-2007 Pierangelo Masarati + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGMENTS: + * This work was initially developed by Pierangelo Masarati for inclusion + * in OpenLDAP Software, sponsored by SysNet s.r.l. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_MEMBEROF + +#include + +#include "ac/string.h" +#include "ac/socket.h" + +#include "slap.h" +#include "config.h" +#include "lutil.h" + +/* + * Glossary: + * + * GROUP a group object (an entry with GROUP_OC + * objectClass) + * MEMBER a member object (an entry whose DN is + * listed as MEMBER_AT value of a GROUP) + * GROUP_OC the objectClass of the group object + * (default: groupOfNames) + * MEMBER_AT the membership attribute, DN-valued; + * note: nameAndOptionalUID is tolerated + * as soon as the optionalUID is absent + * (default: member) + * MEMBER_OF reverse membership attribute + * (default: memberOf) + * + * - add: + * - if the entry that is being added is a GROUP, + * the MEMBER_AT defined as values of the add operation + * get the MEMBER_OF value directly from the request. + * + * if configured to do so, the MEMBER objects do not exist, + * and no relax control is issued, either: + * - fail + * - drop non-existing members + * (by default: don't muck with values) + * + * - if (configured to do so,) the referenced GROUP exists, + * the relax control is set and the user has + * "manage" privileges, allow to add MEMBER_OF values to + * generic entries. + * + * - modify: + * - if the entry being modified is a GROUP_OC and the + * MEMBER_AT attribute is modified, the MEMBER_OF value + * of the (existing) MEMBER_AT entries that are affected + * is modified according to the request: + * - if a MEMBER is removed from the group, + * delete the corresponding MEMBER_OF + * - if a MEMBER is added to a group, + * add the corresponding MEMBER_OF + * + * We need to determine, from the database, if it is + * a GROUP_OC, and we need to check, from the + * modification list, if the MEMBER_AT attribute is being + * affected, and what MEMBER_AT values are affected. + * + * if configured to do so, the entries corresponding to + * the MEMBER_AT values do not exist, and no relax control + * is issued, either: + * - fail + * - drop non-existing members + * (by default: don't muck with values) + * + * - if configured to do so, the referenced GROUP exists, + * (the relax control is set) and the user has + * "manage" privileges, allow to add MEMBER_OF values to + * generic entries; the change is NOT automatically reflected + * in the MEMBER attribute of the GROUP referenced + * by the value of MEMBER_OF; a separate modification, + * with or without relax control, needs to be performed. + * + * - modrdn: + * - if the entry being renamed is a GROUP, the MEMBER_OF + * value of the (existing) MEMBER objects is modified + * accordingly based on the newDN of the GROUP. + * + * We need to determine, from the database, if it is + * a GROUP; the list of MEMBER objects is obtained from + * the database. + * + * Non-existing MEMBER objects are ignored, since the + * MEMBER_AT is not being addressed by the operation. + * + * - if the entry being renamed has the MEMBER_OF attribute, + * the corresponding MEMBER value must be modified in the + * respective group entries. + * + * + * - delete: + * - if the entry being deleted is a GROUP, the (existing) + * MEMBER objects are modified accordingly; a copy of the + * values of the MEMBER_AT is saved and, if the delete + * succeeds, the MEMBER_OF value of the (existing) MEMBER + * objects is deleted. + * + * We need to determine, from the database, if it is + * a GROUP. + * + * Non-existing MEMBER objects are ignored, since the entry + * is being deleted. + * + * - if the entry being deleted has the MEMBER_OF attribute, + * the corresponding value of the MEMBER_AT must be deleted + * from the respective GROUP entries. + */ + +#define SLAPD_MEMBEROF_ATTR "memberOf" + +static slap_overinst memberof; + +typedef struct memberof_t { + struct berval mo_dn; + struct berval mo_ndn; + + ObjectClass *mo_oc_group; + AttributeDescription *mo_ad_member; + AttributeDescription *mo_ad_memberof; + + struct berval mo_groupFilterstr; + AttributeAssertion mo_groupAVA; + Filter mo_groupFilter; + + struct berval mo_memberFilterstr; + Filter mo_memberFilter; + + unsigned mo_flags; +#define MEMBEROF_NONE 0x00U +#define MEMBEROF_FDANGLING_DROP 0x01U +#define MEMBEROF_FDANGLING_ERROR 0x02U +#define MEMBEROF_FDANGLING_MASK (MEMBEROF_FDANGLING_DROP|MEMBEROF_FDANGLING_ERROR) +#define MEMBEROF_FREFINT 0x04U +#define MEMBEROF_FREVERSE 0x08U + +#define MEMBEROF_CHK(mo,f) \ + (((mo)->mo_flags & (f)) == (f)) +#define MEMBEROF_DANGLING_CHECK(mo) \ + ((mo)->mo_flags & MEMBEROF_FDANGLING_MASK) +#define MEMBEROF_DANGLING_DROP(mo) \ + MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_DROP) +#define MEMBEROF_DANGLING_ERROR(mo) \ + MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_ERROR) +#define MEMBEROF_REFINT(mo) \ + MEMBEROF_CHK((mo),MEMBEROF_FREFINT) +#define MEMBEROF_REVERSE(mo) \ + MEMBEROF_CHK((mo),MEMBEROF_FREVERSE) +} memberof_t; + +typedef enum memberof_is_t { + MEMBEROF_IS_NONE = 0x00, + MEMBEROF_IS_GROUP = 0x01, + MEMBEROF_IS_MEMBER = 0x02, + MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER) +} memberof_is_t; + +/* + * failover storage for member attribute values of groups being deleted + * handles [no]thread cases. + */ +static BerVarray saved_member_vals; +static BerVarray saved_memberof_vals; + +static void +memberof_saved_member_free( void *key, void *data ) +{ + ber_bvarray_free( (BerVarray)data ); +} + +static BerVarray +memberof_saved_member_get( Operation *op, void *keyp ) +{ + BerVarray vals; + BerVarray *key = (BerVarray *)keyp; + + assert( op ); + + if ( op->o_threadctx == NULL ) { + vals = *key; + *key = NULL; + + } else { + ldap_pvt_thread_pool_getkey( op->o_threadctx, + key, (void **)&vals, NULL ); + ldap_pvt_thread_pool_setkey( op->o_threadctx, + key, NULL, NULL ); + } + + return vals; +} + +static void +memberof_saved_member_set( Operation *op, void *keyp, BerVarray vals ) +{ + BerVarray saved_vals = NULL; + BerVarray *key = (BerVarray*)keyp; + + assert( op ); + + if ( vals ) { + ber_bvarray_dup_x( &saved_vals, vals, NULL ); + } + + if ( op->o_threadctx == NULL ) { + if ( *key ) { + ber_bvarray_free( *key ); + } + *key = saved_vals; + + } else { + ldap_pvt_thread_pool_setkey( op->o_threadctx, key, + saved_vals, memberof_saved_member_free ); + } +} + +typedef struct memberof_cookie_t { + AttributeDescription *ad; + void *key; + int foundit; +} memberof_cookie_t; + +static int +memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + memberof_cookie_t *mc; + + mc = (memberof_cookie_t *)op->o_callback->sc_private; + mc->foundit = 1; + } + + return 0; +} + +/* + * callback for internal search that saves the member attribute values + * of groups being deleted. + */ +static int +memberof_saveMember_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + memberof_cookie_t *mc; + Attribute *a; + + mc = (memberof_cookie_t *)op->o_callback->sc_private; + mc->foundit = 1; + + assert( rs->sr_entry ); + assert( rs->sr_entry->e_attrs ); + + a = attr_find( rs->sr_entry->e_attrs, mc->ad ); + + assert( a != NULL ); + + memberof_saved_member_set( op, mc->key, a->a_nvals ); + + if ( attr_find( a->a_next, mc->ad ) != NULL ) { + Debug( LDAP_DEBUG_ANY, + "%s: memberof_saveMember_cb(\"%s\"): " + "more than one occurrence of \"%s\" " + "attribute.\n", + op->o_log_prefix, + rs->sr_entry->e_name.bv_val, + mc->ad->ad_cname.bv_val ); + } + } + + return 0; +} + +/* + * the delete hook performs an internal search that saves the member + * attribute values of groups being deleted. + */ +static int +memberof_isGroupOrMember( Operation *op, memberof_is_t *iswhatp ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + Operation op2 = *op; + SlapReply rs2 = { REP_RESULT }; + slap_callback cb = { 0 }; + memberof_cookie_t mc; + AttributeName an[ 2 ]; + + memberof_is_t iswhat = MEMBEROF_IS_NONE; + + assert( iswhatp != NULL ); + assert( *iswhatp != MEMBEROF_IS_NONE ); + + cb.sc_private = &mc; + if ( op->o_tag == LDAP_REQ_DELETE ) { + cb.sc_response = memberof_saveMember_cb; + + } else { + cb.sc_response = memberof_isGroupOrMember_cb; + } + + op2.o_tag = LDAP_REQ_SEARCH; + op2.o_callback = &cb; + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + + op2.ors_scope = LDAP_SCOPE_BASE; + op2.ors_deref = LDAP_DEREF_NEVER; + BER_BVZERO( &an[ 1 ].an_name ); + op2.ors_attrs = an; + op2.ors_attrsonly = 0; + op2.ors_limit = NULL; + op2.ors_slimit = 1; + op2.ors_tlimit = SLAP_NO_LIMIT; + + if ( *iswhatp & MEMBEROF_IS_GROUP ) { + mc.ad = mo->mo_ad_member; + mc.key = &saved_member_vals; + mc.foundit = 0; + an[ 0 ].an_desc = mo->mo_ad_member; + an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; + op2.ors_filterstr = mo->mo_groupFilterstr; + op2.ors_filter = &mo->mo_groupFilter; + + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_search( &op2, &rs2 ); + op2.o_bd->bd_info = (BackendInfo *)on; + + if ( mc.foundit ) { + iswhat |= MEMBEROF_IS_GROUP; + + } else { + memberof_saved_member_set( op, mc.key, NULL ); + } + } + + if ( *iswhatp & MEMBEROF_IS_MEMBER ) { + mc.ad = mo->mo_ad_memberof; + mc.key = &saved_memberof_vals; + mc.foundit = 0; + an[ 0 ].an_desc = mo->mo_ad_memberof; + an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname; + op2.ors_filterstr = mo->mo_memberFilterstr; + op2.ors_filter = &mo->mo_memberFilter; + + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + (void)op->o_bd->be_search( &op2, &rs2 ); + op2.o_bd->bd_info = (BackendInfo *)on; + + if ( mc.foundit ) { + iswhat |= MEMBEROF_IS_MEMBER; + + } else { + memberof_saved_member_set( op, mc.key, NULL ); + } + } + + *iswhatp = iswhat; + + return LDAP_SUCCESS; +} + +/* + * response callback that adds memberof values when a group is modified. + */ +static int +memberof_value_modify( + Operation *op, + SlapReply *rs, + struct berval *ndn, + AttributeDescription *ad, + struct berval *old_dn, + struct berval *old_ndn, + struct berval *new_dn, + struct berval *new_ndn ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + Operation op2 = *op; + SlapReply rs2 = { REP_RESULT }; + slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; + Modifications mod[ 2 ] = { { { 0 } } }, *ml; + struct berval values[ 4 ], nvalues[ 4 ]; + + op2.o_tag = LDAP_REQ_MODIFY; + + op2.o_req_dn = *ndn; + op2.o_req_ndn = *ndn; + + op2.o_bd->bd_info = (BackendInfo *)on->on_info; + + op2.o_callback = &cb; + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + + ml = &mod[ 0 ]; + ml->sml_values = &values[ 0 ]; + ml->sml_values[ 0 ] = mo->mo_dn; + BER_BVZERO( &ml->sml_values[ 1 ] ); + ml->sml_nvalues = &nvalues[ 0 ]; + ml->sml_nvalues[ 0 ] = mo->mo_ndn; + BER_BVZERO( &ml->sml_nvalues[ 1 ] ); + ml->sml_desc = slap_schema.si_ad_modifiersName; + ml->sml_type = ml->sml_desc->ad_cname; + ml->sml_op = LDAP_MOD_REPLACE; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_next = NULL; + op2.orm_modlist = ml; + + ml = &mod[ 1 ]; + ml->sml_values = &values[ 2 ]; + BER_BVZERO( &ml->sml_values[ 1 ] ); + ml->sml_nvalues = &nvalues[ 2 ]; + BER_BVZERO( &ml->sml_nvalues[ 1 ] ); + ml->sml_desc = ad; + ml->sml_type = ml->sml_desc->ad_cname; + ml->sml_flags = SLAP_MOD_INTERNAL; + ml->sml_next = NULL; + op2.orm_modlist->sml_next = ml; + + if ( new_ndn != NULL ) { + assert( !BER_BVISNULL( new_dn ) ); + assert( !BER_BVISNULL( new_ndn ) ); + + ml->sml_op = LDAP_MOD_ADD; + + ml->sml_values[ 0 ] = *new_dn; + ml->sml_nvalues[ 0 ] = *new_ndn; + + (void)op->o_bd->be_modify( &op2, &rs2 ); + + assert( op2.orm_modlist == &mod[ 0 ] ); + assert( op2.orm_modlist->sml_next == &mod[ 1 ] ); + ml = op2.orm_modlist->sml_next->sml_next; + if ( ml != NULL ) { + slap_mods_free( ml, 1 ); + } + } + + if ( old_ndn != NULL ) { + assert( !BER_BVISNULL( old_dn ) ); + assert( !BER_BVISNULL( old_ndn ) ); + + ml->sml_op = LDAP_MOD_DELETE; + + ml->sml_values[ 0 ] = *old_dn; + ml->sml_nvalues[ 0 ] = *old_ndn; + + (void)op->o_bd->be_modify( &op2, &rs2 ); + + assert( op2.orm_modlist == &mod[ 0 ] ); + assert( op2.orm_modlist->sml_next == &mod[ 1 ] ); + ml = op2.orm_modlist->sml_next->sml_next; + if ( ml != NULL ) { + slap_mods_free( ml, 1 ); + } + } + + /* FIXME: if old_group_ndn doesn't exist, both delete __and__ + * add will fail; better split in two operations, although + * not optimal in terms of performance. At least it would + * move towards self-repairing capabilities. */ + + op2.o_bd->bd_info = (BackendInfo *)on; + + return rs2.sr_err; +} + +static int +memberof_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + Attribute **ap, **map = NULL; + int rc = SLAP_CB_CONTINUE; + int i; + struct berval save_dn, save_ndn; + + if ( op->ora_e->e_attrs == NULL ) { + /* FIXME: global overlay; need to deal with */ + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " + "consistency checks not implemented when overlay " + "is instantiated as global.\n", + op->o_log_prefix, op->o_req_dn.bv_val, 0 ); + return SLAP_CB_CONTINUE; + } + + if ( MEMBEROF_REVERSE( mo ) ) { + for ( ap = &op->ora_e->e_attrs; *ap; ap = &(*ap)->a_next ) { + Attribute *a = *ap; + + if ( a->a_desc == mo->mo_ad_memberof ) { + map = ap; + break; + } + } + } + + save_dn = op->o_dn; + save_ndn = op->o_ndn; + + if ( MEMBEROF_DANGLING_CHECK( mo ) + && !get_relax( op ) + && is_entry_objectclass( op->ora_e, mo->mo_oc_group, 0 ) ) + { + op->o_dn = op->o_bd->be_rootdn; + op->o_dn = op->o_bd->be_rootndn; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + + for ( ap = &op->ora_e->e_attrs; *ap; ) { + Attribute *a = *ap; + + if ( !is_ad_subtype( a->a_desc, mo->mo_ad_member ) ) { + ap = &a->a_next; + continue; + } + + assert( a->a_nvals != NULL ); + + for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { + Entry *e; + + /* FIXME: entry_get_rw does not pass + * thru overlays yet; when it does, we + * might need to make a copy of the DN */ + + rc = be_entry_get_rw( op, &a->a_nvals[ i ], + NULL, NULL, 0, &e ); + if ( rc == LDAP_SUCCESS ) { + be_entry_release_r( op, e ); + continue; + } + + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "adding non-existing object " + "as group member"; + send_ldap_result( op, rs ); + goto done; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " + "member=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->ora_e->e_name.bv_val, + a->a_vals[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ); + ber_memfree( a->a_vals[ i ].bv_val ); + BER_BVZERO( &a->a_vals[ i ] ); + if ( a->a_nvals != a->a_vals ) { + ber_memfree( a->a_nvals[ i ].bv_val ); + BER_BVZERO( &a->a_nvals[ i ] ); + } + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + if ( a->a_nvals != a->a_vals ) { + AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + } + i--; + } + } + + /* If all values have been removed, + * remove the attribute itself. */ + if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) { + *ap = a->a_next; + attr_free( a ); + + } else { + ap = &a->a_next; + } + } + op->o_dn = save_dn; + op->o_ndn = save_ndn; + op->o_bd->bd_info = (BackendInfo *)on; + } + + if ( map != NULL ) { + Attribute *a = *map; + AccessControlState acl_state = ACL_STATE_INIT; + + for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { + Entry *e; + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + /* access is checked with the original identity */ + rc = access_allowed( op, op->ora_e, mo->mo_ad_memberof, + &a->a_nvals[ i ], ACL_WADD, + &acl_state ); + if ( rc == 0 ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = NULL; + send_ldap_result( op, rs ); + goto done; + } + rc = be_entry_get_rw( op, &a->a_nvals[ i ], + NULL, NULL, 0, &e ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc != LDAP_SUCCESS ) { + if ( get_relax( op ) ) { + continue; + } + + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "adding non-existing object " + "as memberof"; + send_ldap_result( op, rs ); + goto done; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): " + "memberof=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->ora_e->e_name.bv_val, + a->a_nvals[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ); + ber_memfree( a->a_vals[ i ].bv_val ); + BER_BVZERO( &a->a_vals[ i ] ); + if ( a->a_nvals != a->a_vals ) { + ber_memfree( a->a_nvals[ i ].bv_val ); + BER_BVZERO( &a->a_nvals[ i ] ); + } + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + if ( a->a_nvals != a->a_vals ) { + AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + } + i--; + } + + continue; + } + + /* access is checked with the original identity */ + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = access_allowed( op, e, mo->mo_ad_member, + &op->o_req_ndn, ACL_WADD, NULL ); + be_entry_release_r( op, e ); + op->o_bd->bd_info = (BackendInfo *)on; + + if ( !rc ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "insufficient access to object referenced by memberof"; + send_ldap_result( op, rs ); + goto done; + } + } + + if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) { + *map = a->a_next; + attr_free( a ); + } + } + + rc = SLAP_CB_CONTINUE; + +done:; + op->o_dn = save_dn; + op->o_ndn = save_ndn; + op->o_bd->bd_info = (BackendInfo *)on; + + return rc; +} + +static int +memberof_op_delete( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + memberof_is_t iswhat = MEMBEROF_IS_GROUP; + + if ( MEMBEROF_REFINT( mo ) ) { + iswhat = MEMBEROF_IS_BOTH; + } + + memberof_isGroupOrMember( op, &iswhat ); + + return SLAP_CB_CONTINUE; +} + +static int +memberof_op_modify( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + Modifications **mlp, **mmlp = NULL; + int rc = SLAP_CB_CONTINUE; + struct berval save_dn, save_ndn; + memberof_is_t iswhat = MEMBEROF_IS_GROUP; + + if ( MEMBEROF_REVERSE( mo ) ) { + for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) { + Modifications *ml = *mlp; + + if ( ml->sml_desc == mo->mo_ad_memberof ) { + mmlp = mlp; + break; + } + } + } + + save_dn = op->o_dn; + save_ndn = op->o_ndn; + + if ( MEMBEROF_DANGLING_CHECK( mo ) + && !get_relax( op ) + && memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS + && ( iswhat & MEMBEROF_IS_GROUP ) ) + { + op->o_dn = op->o_bd->be_rootdn; + op->o_dn = op->o_bd->be_rootndn; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + + assert( op->orm_modlist != NULL ); + + for ( mlp = &op->orm_modlist; *mlp; ) { + Modifications *ml = *mlp; + int i; + + if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) { + mlp = &ml->sml_next; + continue; + } + + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + /* we don't care about cancellations: if the value + * exists, fine; if it doesn't, we let the underlying + * database fail as appropriate; */ + mlp = &ml->sml_next; + break; + + case LDAP_MOD_REPLACE: + case LDAP_MOD_ADD: + /* NOTE: right now, the attributeType we use + * for member must have a normalized value */ + assert( ml->sml_nvalues ); + + for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { + int rc; + Entry *e; + + if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ], + NULL, NULL, 0, &e ) == LDAP_SUCCESS ) + { + be_entry_release_r( op, e ); + continue; + } + + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "adding non-existing object " + "as group member"; + send_ldap_result( op, rs ); + goto done; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " + "member=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->o_req_dn.bv_val, + ml->sml_nvalues[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); + ber_memfree( ml->sml_values[ i ].bv_val ); + BER_BVZERO( &ml->sml_values[ i ] ); + ber_memfree( ml->sml_nvalues[ i ].bv_val ); + BER_BVZERO( &ml->sml_nvalues[ i ] ); + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + i--; + } + } + + if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { + *mlp = ml->sml_next; + slap_mod_free( &ml->sml_mod, 0 ); + free( ml ); + + } else { + mlp = &ml->sml_next; + } + + break; + + default: + assert( 0 ); + } + } + } + + if ( mmlp != NULL ) { + Modifications *ml = *mmlp; + int i; + Entry *target; + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = be_entry_get_rw( op, &op->o_req_ndn, + NULL, NULL, 0, &target ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc != LDAP_SUCCESS ) { + rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; + send_ldap_result( op, rs ); + goto done; + } + + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + if ( ml->sml_nvalues != NULL ) { + AccessControlState acl_state = ACL_STATE_INIT; + + for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { + Entry *e; + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + /* access is checked with the original identity */ + rc = access_allowed( op, target, + mo->mo_ad_memberof, + &ml->sml_nvalues[ i ], + ACL_WDEL, + &acl_state ); + if ( rc == 0 ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = NULL; + send_ldap_result( op, rs ); + goto done2; + } + + rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ], + NULL, NULL, 0, &e ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc != LDAP_SUCCESS ) { + if ( get_relax( op ) ) { + continue; + } + + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "deleting non-existing object " + "as memberof"; + send_ldap_result( op, rs ); + goto done2; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " + "memberof=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->o_req_ndn.bv_val, + ml->sml_nvalues[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); + ber_memfree( ml->sml_values[ i ].bv_val ); + BER_BVZERO( &ml->sml_values[ i ] ); + if ( ml->sml_nvalues != ml->sml_values ) { + ber_memfree( ml->sml_nvalues[ i ].bv_val ); + BER_BVZERO( &ml->sml_nvalues[ i ] ); + } + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + if ( ml->sml_nvalues != ml->sml_values ) { + AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + } + i--; + } + + continue; + } + + /* access is checked with the original identity */ + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = access_allowed( op, e, mo->mo_ad_member, + &op->o_req_ndn, + ACL_WDEL, NULL ); + be_entry_release_r( op, e ); + op->o_bd->bd_info = (BackendInfo *)on; + + if ( !rc ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "insufficient access to object referenced by memberof"; + send_ldap_result( op, rs ); + goto done; + } + } + + if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { + *mmlp = ml->sml_next; + slap_mod_free( &ml->sml_mod, 0 ); + free( ml ); + } + + break; + } + /* fall thru */ + + case LDAP_MOD_REPLACE: + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + /* access is checked with the original identity */ + rc = access_allowed( op, target, + mo->mo_ad_memberof, + NULL, + ACL_WDEL, NULL ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc == 0 ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = NULL; + send_ldap_result( op, rs ); + goto done2; + } + + if ( ml->sml_op == LDAP_MOD_DELETE ) { + break; + } + /* fall thru */ + + case LDAP_MOD_ADD: { + AccessControlState acl_state = ACL_STATE_INIT; + + for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) { + Entry *e; + + op->o_bd->bd_info = (BackendInfo *)on->on_info; + /* access is checked with the original identity */ + rc = access_allowed( op, target, + mo->mo_ad_memberof, + &ml->sml_nvalues[ i ], + ACL_WADD, + &acl_state ); + if ( rc == 0 ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = NULL; + send_ldap_result( op, rs ); + goto done2; + } + + rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ], + NULL, NULL, 0, &e ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc != LDAP_SUCCESS ) { + if ( MEMBEROF_DANGLING_ERROR( mo ) ) { + rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; + rs->sr_text = "adding non-existing object " + "as memberof"; + send_ldap_result( op, rs ); + goto done2; + } + + if ( MEMBEROF_DANGLING_DROP( mo ) ) { + int j; + + Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): " + "memberof=\"%s\" does not exist (stripping...)\n", + op->o_log_prefix, op->o_req_ndn.bv_val, + ml->sml_nvalues[ i ].bv_val ); + + for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ ); + ber_memfree( ml->sml_values[ i ].bv_val ); + BER_BVZERO( &ml->sml_values[ i ] ); + if ( ml->sml_nvalues != ml->sml_values ) { + ber_memfree( ml->sml_nvalues[ i ].bv_val ); + BER_BVZERO( &ml->sml_nvalues[ i ] ); + } + if ( j - i == 1 ) { + break; + } + + AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + if ( ml->sml_nvalues != ml->sml_values ) { + AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ], + sizeof( struct berval ) * ( j - i ) ); + } + i--; + } + + continue; + } + + /* access is checked with the original identity */ + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = access_allowed( op, e, mo->mo_ad_member, + &op->o_req_ndn, + ACL_WDEL, NULL ); + be_entry_release_r( op, e ); + op->o_bd->bd_info = (BackendInfo *)on; + + if ( !rc ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "insufficient access to object referenced by memberof"; + send_ldap_result( op, rs ); + goto done; + } + } + + if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) { + *mmlp = ml->sml_next; + slap_mod_free( &ml->sml_mod, 0 ); + free( ml ); + } + + } break; + + default: + assert( 0 ); + } + +done2:; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + be_entry_release_r( op, target ); + op->o_bd->bd_info = (BackendInfo *)on; + } + + rc = SLAP_CB_CONTINUE; + +done:; + op->o_dn = save_dn; + op->o_ndn = save_ndn; + op->o_bd->bd_info = (BackendInfo *)on; + + return rc; +} + +/* + * response callback that adds memberof values when a group is added. + */ +static int +memberof_res_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + int i; + + if ( MEMBEROF_REVERSE( mo ) ) { + Attribute *ma; + + ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof ); + if ( ma != NULL ) { + Operation op2 = *op; + SlapReply rs2 = { 0 }; + + /* relax is required to allow to add + * a non-existing member */ + op2.o_relax = SLAP_CONTROL_CRITICAL; + + for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) { + + /* the modification is attempted + * with the original identity */ + (void)memberof_value_modify( &op2, &rs2, + &ma->a_nvals[ i ], mo->mo_ad_member, + NULL, NULL, &op->o_req_dn, &op->o_req_ndn ); + } + } + } + + if ( is_entry_objectclass( op->ora_e, mo->mo_oc_group, 0 ) ) { + Attribute *a; + + for ( a = attrs_find( op->ora_e->e_attrs, mo->mo_ad_member ); + a != NULL; + a = attrs_find( a->a_next, mo->mo_ad_member ) ) + { + for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &a->a_nvals[ i ], + mo->mo_ad_memberof, + NULL, NULL, + &op->o_req_dn, + &op->o_req_ndn ); + } + } + } + + return SLAP_CB_CONTINUE; +} + +/* + * response callback that deletes memberof values when a group is deleted. + */ +static int +memberof_res_delete( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + BerVarray vals; + int i; + + vals = memberof_saved_member_get( op, &saved_member_vals ); + if ( vals != NULL ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_memberof, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + + ber_bvarray_free( vals ); + } + + if ( MEMBEROF_REFINT( mo ) ) { + vals = memberof_saved_member_get( op, &saved_memberof_vals ); + if ( vals != NULL ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_member, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + + ber_bvarray_free( vals ); + } + } + + return SLAP_CB_CONTINUE; +} + +/* + * response callback that adds/deletes memberof values when a group + * is modified. + */ +static int +memberof_res_modify( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + int i, rc; + Modifications *ml, *mml = NULL; + BerVarray vals; + memberof_is_t iswhat = MEMBEROF_IS_GROUP; + + if ( MEMBEROF_REVERSE( mo ) ) { + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + if ( ml->sml_desc == mo->mo_ad_memberof ) { + mml = ml; + break; + } + } + } + + if ( mml != NULL ) { + BerVarray vals = mml->sml_nvalues; + + switch ( mml->sml_op ) { + case LDAP_MOD_DELETE: + if ( vals != NULL ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_member, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + break; + } + /* fall thru */ + + case LDAP_MOD_REPLACE: + /* delete all ... */ + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = backend_attribute( op, NULL, &op->o_req_ndn, + mo->mo_ad_memberof, &vals, ACL_READ ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc == LDAP_SUCCESS ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_member, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } + + if ( ml->sml_op == LDAP_MOD_DELETE ) { + break; + } + /* fall thru */ + + case LDAP_MOD_ADD: + assert( vals != NULL ); + + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_member, + NULL, NULL, + &op->o_req_dn, &op->o_req_ndn ); + } + break; + + default: + assert( 0 ); + } + } + + if ( memberof_isGroupOrMember( op, &iswhat ) == LDAP_SUCCESS + && ( iswhat & MEMBEROF_IS_GROUP ) ) + { + for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) { + if ( ml->sml_desc != mo->mo_ad_member ) { + continue; + } + + switch ( ml->sml_op ) { + case LDAP_MOD_DELETE: + vals = ml->sml_nvalues; + if ( vals != NULL ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_memberof, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + break; + } + /* fall thru */ + + case LDAP_MOD_REPLACE: + /* delete all ... */ + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = backend_attribute( op, NULL, &op->o_req_ndn, + mo->mo_ad_member, &vals, ACL_READ ); + op->o_bd->bd_info = (BackendInfo *)on; + if ( rc == LDAP_SUCCESS ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_memberof, + &op->o_req_dn, &op->o_req_ndn, + NULL, NULL ); + } + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } + + if ( ml->sml_op == LDAP_MOD_DELETE ) { + break; + } + /* fall thru */ + + case LDAP_MOD_ADD: + assert( ml->sml_nvalues != NULL ); + vals = ml->sml_nvalues; + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_memberof, + NULL, NULL, + &op->o_req_dn, &op->o_req_ndn ); + } + break; + + default: + assert( 0 ); + } + } + } + + return SLAP_CB_CONTINUE; +} + +/* + * response callback that adds/deletes member values when a group member + * is modified. + */ +static int +memberof_res_rename( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + struct berval newPDN, newDN = BER_BVNULL, newPNDN, newNDN; + int i, rc; + BerVarray vals; + + struct berval save_dn, save_ndn; + memberof_is_t iswhat = MEMBEROF_IS_GROUP; + + if ( MEMBEROF_REFINT( mo ) ) { + iswhat |= MEMBEROF_IS_MEMBER; + } + + if ( op->orr_nnewSup ) { + newPNDN = *op->orr_nnewSup; + + } else { + dnParent( &op->o_req_ndn, &newPNDN ); + } + + build_new_dn( &newNDN, &newPNDN, &op->orr_nnewrdn, op->o_tmpmemctx ); + + save_dn = op->o_req_dn; + save_ndn = op->o_req_ndn; + + op->o_req_dn = newNDN; + op->o_req_ndn = newNDN; + rc = memberof_isGroupOrMember( op, &iswhat ); + op->o_req_dn = save_dn; + op->o_req_ndn = save_ndn; + + if ( rc != LDAP_SUCCESS || iswhat == MEMBEROF_IS_NONE ) { + goto done; + } + + if ( op->orr_newSup ) { + newPDN = *op->orr_newSup; + + } else { + dnParent( &op->o_req_dn, &newPDN ); + } + + build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx ); + + if ( iswhat & MEMBEROF_IS_GROUP ) { + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = backend_attribute( op, NULL, &newNDN, + mo->mo_ad_member, &vals, ACL_READ ); + op->o_bd->bd_info = (BackendInfo *)on; + + if ( rc == LDAP_SUCCESS ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_memberof, + &op->o_req_dn, &op->o_req_ndn, + &newDN, &newNDN ); + } + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } + } + + if ( MEMBEROF_REFINT( mo ) && ( iswhat & MEMBEROF_IS_MEMBER ) ) { + op->o_bd->bd_info = (BackendInfo *)on->on_info; + rc = backend_attribute( op, NULL, &newNDN, + mo->mo_ad_memberof, &vals, ACL_READ ); + op->o_bd->bd_info = (BackendInfo *)on; + + if ( rc == LDAP_SUCCESS ) { + for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) { + (void)memberof_value_modify( op, rs, + &vals[ i ], mo->mo_ad_member, + &op->o_req_dn, &op->o_req_ndn, + &newDN, &newNDN ); + } + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } + } + +done:; + if ( !BER_BVISNULL( &newDN ) ) { + op->o_tmpfree( newDN.bv_val, op->o_tmpmemctx ); + } + op->o_tmpfree( newNDN.bv_val, op->o_tmpmemctx ); + + return SLAP_CB_CONTINUE; +} + +static int +memberof_response( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_err != LDAP_SUCCESS ) { + return SLAP_CB_CONTINUE; + } + + switch ( op->o_tag ) { + case LDAP_REQ_ADD: + return memberof_res_add( op, rs ); + + case LDAP_REQ_DELETE: + return memberof_res_delete( op, rs ); + + case LDAP_REQ_MODIFY: + return memberof_res_modify( op, rs ); + + case LDAP_REQ_MODDN: + return memberof_res_rename( op, rs ); + + default: + return SLAP_CB_CONTINUE; + } +} + +static int +memberof_db_init( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + memberof_t *mo; + + int rc; + const char *text = NULL; + + mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) ); + + rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &mo->mo_ad_memberof, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "memberof_db_init: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_MEMBEROF_ATTR, text, rc ); + return rc; + } + + rc = slap_str2ad( SLAPD_GROUP_ATTR, &mo->mo_ad_member, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "memberof_db_init: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_GROUP_ATTR, text, rc ); + return rc; + } + + mo->mo_oc_group = oc_find( SLAPD_GROUP_CLASS ); + if ( mo->mo_oc_group == NULL ) { + Debug( LDAP_DEBUG_ANY, + "memberof_db_init: " + "unable to find objectClass=\"%s\"\n", + SLAPD_GROUP_CLASS, 0, 0 ); + return 1; + } + + on->on_bi.bi_private = (void *)mo; + + return 0; +} + +enum { + MO_DN = 1, + MO_DANGLING, + MO_REFINT, +#if 0 + MO_REVERSE, +#endif + MO_GROUP_OC, + MO_MEMBER_AD, + MO_MEMBER_OF_AD +}; + +static ConfigDriver mo_cf_gen; + +#define OID "1.3.6.1.4.1.7136.2.666.4" +#define OIDAT OID ".1.1" +#define OIDCFGAT OID ".1.2" +#define OIDOC OID ".2.1" +#define OIDCFGOC OID ".2.2" + + +static ConfigTable mo_cfg[] = { + { "memberof-dn", "modifiersName", + 2, 2, 0, ARG_MAGIC|ARG_DN|MO_DN, mo_cf_gen, + "( OLcfgOvAt:18.0 NAME 'olcMemberOfDN' " + "DESC 'DN to be used as modifiersName' " + "SYNTAX OMsDN SINGLE-VALUE )", + NULL, NULL }, + + { "memberof-dangling", "ignore|drop|error", + 2, 2, 0, ARG_MAGIC|MO_DANGLING, mo_cf_gen, + "( OLcfgOvAt:18.1 NAME 'olcMemberOfDangling' " + "DESC 'Behavior with respect to dangling members, " + "constrained to ignore, drop, error' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + + { "memberof-refint", "true|FALSE", + 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REFINT, mo_cf_gen, + "( OLcfgOvAt:18.2 NAME 'olcMemberOfRefInt' " + "DESC 'Take care of referential integrity' " + "SYNTAX OMsBoolean SINGLE-VALUE )", + NULL, NULL }, + + { "memberof-group-oc", "objectClass", + 2, 2, 0, ARG_MAGIC|MO_GROUP_OC, mo_cf_gen, + "( OLcfgOvAt:18.3 NAME 'olcMemberOfGroupOC' " + "DESC 'Group objectClass' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + + { "memberof-member-ad", "member attribute", + 2, 2, 0, ARG_MAGIC|MO_MEMBER_AD, mo_cf_gen, + "( OLcfgOvAt:18.4 NAME 'olcMemberOfMemberAD' " + "DESC 'member attribute' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + + { "memberof-memberof-ad", "memberOf attribute", + 2, 2, 0, ARG_MAGIC|MO_MEMBER_OF_AD, mo_cf_gen, + "( OLcfgOvAt:18.5 NAME 'olcMemberOfMemberOfAD' " + "DESC 'memberOf attribute' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", + NULL, NULL }, + +#if 0 + { "memberof-reverse", "true|FALSE", + 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REVERSE, mo_cf_gen, + "( OLcfgOvAt:18.6 NAME 'olcMemberOfReverse' " + "DESC 'Take care of referential integrity " + "also when directly modifying memberOf' " + "SYNTAX OMsBoolean SINGLE-VALUE )", + NULL, NULL }, +#endif + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs mo_ocs[] = { + { "( OLcfgOvOc:18.1 " + "NAME 'olcMemberOf' " + "DESC 'Member-of configuration' " + "SUP olcOverlayConfig " + "MAY ( " + "olcMemberOfDN " + "$ olcMemberOfDangling " + "$ olcMemberOfRefInt " + "$ olcMemberOfGroupOC " + "$ olcMemberOfMemberAD " + "$ olcMemberOfMemberOfAD " +#if 0 + "$ olcMemberOfReverse " +#endif + ") " + ")", + Cft_Overlay, mo_cfg, NULL, NULL }, + { NULL, 0, NULL } +}; + +static slap_verbmasks dangling_mode[] = { + { BER_BVC( "ignore" ), MEMBEROF_NONE }, + { BER_BVC( "drop" ), MEMBEROF_FDANGLING_DROP }, + { BER_BVC( "error" ), MEMBEROF_FDANGLING_ERROR }, + { BER_BVNULL, 0 } +}; + +static int +memberof_make_group_filter( memberof_t *mo ) +{ + char *ptr; + + if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) { + ch_free( mo->mo_groupFilterstr.bv_val ); + } + + mo->mo_groupFilter.f_choice = LDAP_FILTER_EQUALITY; + mo->mo_groupFilter.f_ava = &mo->mo_groupAVA; + + mo->mo_groupFilter.f_av_desc = slap_schema.si_ad_objectClass; + mo->mo_groupFilter.f_av_value = mo->mo_oc_group->soc_cname; + + mo->mo_groupFilterstr.bv_len = STRLENOF( "(=)" ) + + slap_schema.si_ad_objectClass->ad_cname.bv_len + + mo->mo_oc_group->soc_cname.bv_len; + ptr = mo->mo_groupFilterstr.bv_val = ch_malloc( mo->mo_groupFilterstr.bv_len + 1 ); + *ptr++ = '('; + ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val ); + *ptr++ = '='; + ptr = lutil_strcopy( ptr, mo->mo_oc_group->soc_cname.bv_val ); + *ptr++ = ')'; + *ptr = '\0'; + + return 0; +} + +static int +memberof_make_member_filter( memberof_t *mo ) +{ + char *ptr; + + if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) { + ch_free( mo->mo_memberFilterstr.bv_val ); + } + + mo->mo_memberFilter.f_choice = LDAP_FILTER_PRESENT; + mo->mo_memberFilter.f_desc = mo->mo_ad_memberof; + + mo->mo_memberFilterstr.bv_len = STRLENOF( "(=*)" ) + + mo->mo_ad_memberof->ad_cname.bv_len; + ptr = mo->mo_memberFilterstr.bv_val = ch_malloc( mo->mo_memberFilterstr.bv_len + 1 ); + *ptr++ = '('; + ptr = lutil_strcopy( ptr, mo->mo_ad_memberof->ad_cname.bv_val ); + ptr = lutil_strcopy( ptr, "=*)" ); + + return 0; +} + +static int +mo_cf_gen( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + int i, rc = 0; + + if ( c->op == SLAP_CONFIG_EMIT ) { + struct berval bv = BER_BVNULL; + + switch( c->type ) { + case MO_DN: + value_add_one( &c->rvalue_vals, &mo->mo_dn ); + value_add_one( &c->rvalue_nvals, &mo->mo_ndn ); + break; + + case MO_DANGLING: + enum_to_verb( dangling_mode, (mo->mo_flags & MEMBEROF_FDANGLING_MASK), &bv ); + if ( BER_BVISNULL( &bv ) ) { + /* there's something wrong... */ + assert( 0 ); + rc = 1; + + } else { + value_add_one( &c->rvalue_vals, &bv ); + } + break; + + case MO_REFINT: + c->value_int = MEMBEROF_REFINT( mo ); + break; + +#if 0 + case MO_REVERSE: + c->value_int = MEMBEROF_REVERSE( mo ); + break; +#endif + + case MO_GROUP_OC: + assert( mo->mo_oc_group != NULL ); + value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname ); + break; + + case MO_MEMBER_AD: + assert( mo->mo_ad_member != NULL ); + value_add_one( &c->rvalue_vals, &mo->mo_ad_member->ad_cname ); + break; + + case MO_MEMBER_OF_AD: + assert( mo->mo_ad_memberof != NULL ); + value_add_one( &c->rvalue_vals, &mo->mo_ad_memberof->ad_cname ); + break; + + default: + assert( 0 ); + return 1; + } + + return rc; + + } else if ( c->op == LDAP_MOD_DELETE ) { + return 1; /* FIXME */ + + } else { + switch( c->type ) { + case MO_DN: + if ( !BER_BVISNULL( &mo->mo_dn ) ) { + ber_memfree( mo->mo_dn.bv_val ); + ber_memfree( mo->mo_ndn.bv_val ); + } + mo->mo_dn = c->value_dn; + mo->mo_ndn = c->value_ndn; + break; + + case MO_DANGLING: + i = verb_to_mask( c->argv[ 1 ], dangling_mode ); + if ( BER_BVISNULL( &dangling_mode[ i ].word ) ) { + return 1; + } + + mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK; + mo->mo_flags |= dangling_mode[ i ].mask; + break; + + case MO_REFINT: + if ( c->value_int ) { + mo->mo_flags |= MEMBEROF_FREFINT; + + } else { + mo->mo_flags &= ~MEMBEROF_FREFINT; + } + break; + +#if 0 + case MO_REVERSE: + if ( c->value_int ) { + mo->mo_flags |= MEMBEROF_FREVERSE; + + } else { + mo->mo_flags &= ~MEMBEROF_FREVERSE; + } + break; +#endif + + case MO_GROUP_OC: { + ObjectClass *oc = NULL; + + oc = oc_find( c->argv[ 1 ] ); + if ( oc == NULL ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "unable to find group objectClass=\"%s\"", + c->argv[ 1 ] ); + Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + mo->mo_oc_group = oc; + memberof_make_group_filter( mo ); + } break; + + case MO_MEMBER_AD: { + AttributeDescription *ad = NULL; + const char *text = NULL; + + + rc = slap_str2ad( c->argv[ 1 ], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "unable to find member attribute=\"%s\": %s (%d)", + c->argv[ 1 ], text, rc ); + Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ + && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ + { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "member attribute=\"%s\" must either " + "have DN (%s) or nameUID (%s) syntax", + c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); + Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + mo->mo_ad_member = ad; + } break; + + case MO_MEMBER_OF_AD: { + AttributeDescription *ad = NULL; + const char *text = NULL; + + + rc = slap_str2ad( c->argv[ 1 ], &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "unable to find memberof attribute=\"%s\": %s (%d)", + c->argv[ 1 ], text, rc ); + Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */ + && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */ + { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "memberof attribute=\"%s\" must either " + "have DN (%s) or nameUID (%s) syntax", + c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); + Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", + c->log, c->cr_msg, 0 ); + return 1; + } + + mo->mo_ad_memberof = ad; + memberof_make_member_filter( mo ); + } break; + + default: + assert( 0 ); + return 1; + } + } + + return 0; +} + +static int +memberof_db_open( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + if ( BER_BVISNULL( &mo->mo_dn ) ) { + ber_dupbv( &mo->mo_dn, &be->be_rootdn ); + ber_dupbv( &mo->mo_ndn, &be->be_rootndn ); + } + + if ( BER_BVISNULL( &mo->mo_groupFilterstr ) ) { + memberof_make_group_filter( mo ); + } + + if ( BER_BVISNULL( &mo->mo_memberFilterstr ) ) { + memberof_make_member_filter( mo ); + } + + return 0; +} + +static int +memberof_db_destroy( + BackendDB *be, + ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + memberof_t *mo = (memberof_t *)on->on_bi.bi_private; + + if ( mo ) { + if ( !BER_BVISNULL( &mo->mo_dn ) ) { + ber_memfree( mo->mo_dn.bv_val ); + ber_memfree( mo->mo_ndn.bv_val ); + } + + if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) { + ber_memfree( mo->mo_groupFilterstr.bv_val ); + } + + if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) { + ber_memfree( mo->mo_memberFilterstr.bv_val ); + } + + ber_memfree( mo ); + } + + return 0; +} + +/* unused */ +static AttributeDescription *ad_memberOf; + +static struct { + char *desc; + AttributeDescription **adp; +} as[] = { + { "( 1.2.840.113556.1.2.102 " + "NAME 'memberOf' " + "DESC 'Group that the entry belongs to' " + "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' " + "EQUALITY distinguishedNameMatch " /* added */ + "USAGE dSAOperation " /* added; questioned */ + /* "NO-USER-MODIFICATION " */ /* add? */ + "X-ORIGIN 'iPlanet Delegated Administrator' )", + &ad_memberOf }, + { NULL } +}; + +#if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC +static +#endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */ +int +memberof_initialize( void ) +{ + int code, i; + + for ( i = 0; as[ i ].desc != NULL; i++ ) { + code = register_at( as[ i ].desc, as[ i ].adp, 0 ); + if ( code ) { + Debug( LDAP_DEBUG_ANY, + "memberof_initialize: register_at #%d failed\n", + i, 0, 0 ); + return code; + } + } + + memberof.on_bi.bi_type = "memberof"; + + memberof.on_bi.bi_db_init = memberof_db_init; + memberof.on_bi.bi_db_open = memberof_db_open; + memberof.on_bi.bi_db_destroy = memberof_db_destroy; + + memberof.on_bi.bi_op_add = memberof_op_add; + memberof.on_bi.bi_op_delete = memberof_op_delete; + memberof.on_bi.bi_op_modify = memberof_op_modify; + + memberof.on_response = memberof_response; + + memberof.on_bi.bi_cf_ocs = mo_ocs; + + code = config_register_schema( mo_cfg, mo_ocs ); + if ( code ) return code; + + return overlay_register( &memberof ); +} + +#if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return memberof_initialize(); +} +#endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */ + +#endif /* SLAPD_OVER_MEMBEROF */ diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index 56bf2a29b2..ae3690c652 100644 --- a/servers/slapd/overlays/pcache.c +++ b/servers/slapd/overlays/pcache.c @@ -35,6 +35,19 @@ #include "config.h" +#ifdef LDAP_DEVEL +/* + * Control that allows to access the private DB + * instead of the public one + */ +#define PCACHE_CONTROL_PRIVDB "1.3.6.1.4.1.4203.666.11.9.5.1" + +/* + * Extended Operation that allows to remove a query from the cache + */ +#define PCACHE_EXOP_QUERY_DELETE "1.3.6.1.4.1.4203.666.11.9.6.1" +#endif + /* query cache structs */ /* query */ @@ -59,7 +72,7 @@ typedef struct cached_query_s { Qbase *qbase; int scope; struct berval q_uuid; /* query identifier */ - struct query_template_s *qtemp; /* template of the query */ + struct query_template_s *qtemp; /* template of the query */ time_t expiry_time; /* time till the query is considered valid */ struct cached_query_s *next; /* next query in the template */ struct cached_query_s *prev; /* previous query in the template */ @@ -67,6 +80,22 @@ typedef struct cached_query_s { struct cached_query_s *lru_down; /* next query in the LRU list */ } CachedQuery; +/* + * URL representation: + * + * ldap:///????x-uuid=,x-template=